From f533f5050bb4899e18dc1656458697b1d277dd56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Fri, 2 Oct 2020 16:49:43 +0200 Subject: Binding of fields in edit tab work. --- module/calp/html/vcomponent.scm | 50 +++++++++++++++++----- static/script.js | 91 +++++++++++++++++++++-------------------- 2 files changed, 86 insertions(+), 55 deletions(-) diff --git a/module/calp/html/vcomponent.scm b/module/calp/html/vcomponent.scm index 7a4de873..0f8014db 100644 --- a/module/calp/html/vcomponent.scm +++ b/module/calp/html/vcomponent.scm @@ -56,18 +56,21 @@ ;; (format (current-error-port) "fmt-single-event: ~a~%" (prop ev 'X-HNH-FILENAME)) `(div (@ ,@(assq-merge attributes - `((class " eventtext " + `((class " eventtext summary-tab " ,(when (and (prop ev 'PARTSTAT) (eq? 'TENTATIVE (prop ev 'PARTSTAT))) " tentative "))))) (h3 ,(fmt-header (when (prop ev 'RRULE) `(span (@ (class "repeating")) "↺")) - `(span (@ (class "summary")) ,(prop ev 'SUMMARY)))) + `(span (@ (class "bind summary") + (data-property "summary")) + ,(prop ev 'SUMMARY)))) (div ,(call-with-values (lambda () (fmt-time-span ev)) (case-lambda [(start) - `(div (time (@ (class "dtstart") + `(div (time (@ (class "bind dtstart") + (data-property "dtstart") (data-fmt ,(string-append "~L" start)) (datetime ,(datetime->string (as-datetime (prop ev 'DTSTART)) @@ -76,7 +79,8 @@ (as-datetime (prop ev 'DTSTART)) start)))] [(start end) - `(div (time (@ (class "dtstart") + `(div (time (@ (class "bind dtstart") + (data-property "dtstart") (data-fmt ,(string-append "~L" start)) (datetime ,(datetime->string (as-datetime (prop ev 'DTSTART)) @@ -84,23 +88,30 @@ ,(datetime->string (as-datetime (prop ev 'DTSTART)) start)) " — " - (time (@ (class "dtend") + (time (@ (class "bind dtend") + (data-property "dtend") (data-fmt ,(string-append "~L" end)) (datetime ,(datetime->string (as-datetime (prop ev 'DTSTART)) "~1T~3"))) ,(datetime->string (as-datetime (prop ev 'DTEND)) end)))])) + + ;; TODO add optional fields when added in frontend + ;; Possibly by always having them here, just hidden. + (div (@ (class "fields")) ,(when (and=> (prop ev 'LOCATION) (negate string-null?)) `(div (b "Plats: ") - (div (@ (class "location")) + (div (@ (class "bind location") (data-property "location")) ,(string-map (lambda (c) (if (char=? c #\,) #\newline c)) (prop ev 'LOCATION))))) ,(awhen (prop ev 'DESCRIPTION) - `(div (@ (class "description")) + `(div (@ (class "bind description") + (data-property "description")) ,(format-description ev it))) + ;; TODO add bind once I figure out how to bind lists ,(awhen (prop ev 'CATEGORIES) `(div (@ (class "categories")) ,@(map (lambda (c) @@ -111,6 +122,8 @@ c))) ,c)) it))) + + ;; TODO bind ,(awhen (prop ev 'RRULE) `(div (@ (class "rrule")) ,@(format-recurrence-rule ev))) @@ -124,11 +137,12 @@ (define*-public (fmt-for-edit ev optional: (attributes '()) key: (fmt-header list)) - `(div (@ (class " eventtext ")) + `(div (@ (class " eventtext edit-tab ")) (form (@ (class "edit-form")) (h3 (input (@ (type "text") (placeholder "Sammanfattning") (name "summary") (required) + (class "bind") (data-property "summary") (value ,(prop ev 'SUMMARY))))) ,(let ((start (prop ev 'DTSTART)) @@ -138,11 +152,15 @@ (input (@ (type "date") (name "dtstart-date") (style "grid-column:1;grid-row:2") + (class "bind") + (data-property "--dtstart-date") (value ,(date->string (as-date start))))) (input (@ (type "date") (name "dtend-date") (style "grid-column:1;grid-row:3") + (class "bind") + (data-property "--dtend-date") ,@(when end `((value ,(date->string (as-date end))))))) ,@(with-label @@ -151,13 +169,17 @@ (name "wholeday")))) (input (@ (type "time") - (name "dtstart-end") + (name "dtstart-time") + (class "bind") + (data-property "--dtstart-time") (style "grid-column:3;grid-row:2;" ,(when (date? start) "display:none")) (value ,(time->string (as-time start))))) (input (@ (type "time") (name "dtend-time") + (class "bind") + (data-property "--dtend-time") (style "grid-column:3;grid-row:3;" ,(when (date? end) "display:none")) ,@(when end `((value ,(time->string (as-time end))))) @@ -168,11 +190,13 @@ `(input (@ (placeholder "Plats") (name "location") (type "text") + (class "bind") (data-property "location") (value ,(or (prop ev 'LOCATION) ""))))) ,@(with-label "Beskrivning" `(textarea (@ (placeholder "Beskrivning") + (class "bind") (data-property "description") (name "description")) ,(prop ev 'DESCRIPTION))) @@ -190,6 +214,8 @@ (type "text") )))) + ;; TODO extra fields + (hr) (div (@ (class "newfield")) @@ -275,10 +301,12 @@ (div (@ (class "event-body")) ,(when (prop ev 'RRULE) `(span (@ (class "repeating")) "↺")) - (span (@ (class "summary")) + (span (@ (class "bind summary") + (data-property "summary")) ,(format-summary ev (prop ev 'SUMMARY))) ,(when (prop ev 'LOCATION) - `(span (@ (class "location")) + `(span (@ (class "bind location") + (data-property "location")) ,(string-map (lambda (c) (if (char=? c #\,) #\newline c)) (prop ev 'LOCATION))))) (div (@ (style "display:none !important;")) diff --git a/static/script.js b/static/script.js index 7fcdf48f..b703a21a 100644 --- a/static/script.js +++ b/static/script.js @@ -928,7 +928,7 @@ function toggle_popup(popup_id) { 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, bind_to_ical=true) { +function get_property(el, field, default_value) { if (! el.properties) { el.properties = {}; } @@ -952,20 +952,6 @@ function get_property(el, field, default_value, bind_to_ical=true) { }); } - if (bind_to_ical) { - let ical_properties = el.querySelector("icalendar vevent properties"); - if (! ical_properties.querySelector(field)) { - let text = document.createElementNS(xcal, 'text'); - let element = document.createElementNS(xcal, field); - element.appendChild(text); - if (default_value) {text.innerHTML = default_value;} - - ical_properties.appendChild(element); - el.properties["_slot_" + field].push( - [text, (s, v) => s.innerHTML = v]); - } - } - return el.properties["_slot_" + field]; } @@ -1001,45 +987,61 @@ class vcomponent { and binds the value to the slot. */ function bind_properties (el, wide_event=false) { + el.properties = {} let popup = document.getElementById("popup" + el.id); // let children = el.getElementsByTagName("properties")[0].children; - let children = el.querySelector("vevent > properties").children; - for (let child of children) { - let field = child.tagName; + /* actual component (not popup) */ + for (let e of el.querySelectorAll(".bind")) { + let f = ((s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt)); + get_property(el, e.dataset.property).push([e, f]); + } - let lst = get_property(el, field); + /* primary display tab */ - /* Bind HTML fields for this event */ - for (let s of el.getElementsByClassName(field)) { - let f = ((s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt)); - lst.push([s, f]); + for (let e of popup.querySelectorAll(".summary-tab .bind")) { + 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")) { + let p = get_property(el, e.dataset.property); + e.oninput = function () { + el.properties[e.dataset.property] = this.value; } - for (let s of popup.getElementsByClassName(field)) { - let f = ((s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt)); - lst.push([s, f]); + let f; + switch (e.tagName) { + case 'input': + // TODO format depending on type + switch (e.type) { + case 'time': f = (s, v) => s.value = v.format("~H:~M:~S"); break; + case 'date': f = (s, v) => s.value = v.format("~Y-~m-~d"); break; + 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; } + } - /* edit tab */ - for (let s of popup.querySelectorAll(`[name='${field}']`)) { - let f; - s.oninput = function () { - el.properties[s.name] = this.value; - } - switch (s.name) { - case 'description': - f = ((s, v) => s.innerHTML = v.format(s.dataset && s.dataset.fmt)); - lst.push([s, f]); - break; - default: - f = ((s, v) => s.value = v); - lst.push([s, f]); - break; - } - } + /* TODO propagate `--dtstart-*' to `dtstart' */ + get_property(el, 'dtstart').push( + [el, (el, v) => { el.properties['--dtstart-time'] = v; + el.properties['--dtstart-date'] = v; }]); + for (let child of el.querySelector("vevent > properties").children) { + let field = child.tagName; + + let lst = get_property(el, field); /* Bind vcomponent fields for this event */ for (let s of el.querySelectorAll(field + " > :not(parameters)")) { @@ -1055,6 +1057,7 @@ function bind_properties (el, wide_event=false) { } } + /* set up graphical display changes */ let container = el.closest(".event-container"); if (container === null) { console.log("No enclosing event container for", el); @@ -1087,7 +1090,7 @@ function bind_properties (el, wide_event=false) { el.dataset.calendar = "Unknown"; } - let calprop = get_property(el, 'calendar', el.dataset.calendar, false); + let calprop = get_property(el, 'calendar', el.dataset.calendar); const rplcs = (s, v) => { let [_, calclass] = s.classList.find(/^CAL_/); -- cgit v1.2.3