diff options
-rw-r--r-- | module/calp/html/vcomponent.scm | 27 | ||||
-rw-r--r-- | module/calp/html/view/calendar.scm | 65 | ||||
-rw-r--r-- | module/calp/html/view/calendar/week.scm | 11 | ||||
-rw-r--r-- | static/components/edit-rrule.ts | 18 | ||||
-rw-r--r-- | static/components/vevent-edit.ts | 6 | ||||
-rw-r--r-- | static/jcal.ts | 14 | ||||
-rw-r--r-- | static/vevent.ts | 2 |
7 files changed, 103 insertions, 40 deletions
diff --git a/module/calp/html/vcomponent.scm b/module/calp/html/vcomponent.scm index bff219aa..4c42d597 100644 --- a/module/calp/html/vcomponent.scm +++ b/module/calp/html/vcomponent.scm @@ -15,6 +15,7 @@ :use-module ((calp util color) :select (calculate-fg-color)) :use-module ((crypto) :select (sha256 checksum->string)) :use-module ((xdg basedir) :prefix xdg-) + :use-module ((vcomponent recurrence) :select (repeating?)) :use-module ((vcomponent recurrence internal) :prefix #{rrule:}#) :use-module ((vcomponent datetime output) :select (fmt-time-span @@ -414,7 +415,7 @@ extra-attributes `((id ,(html-id ev)) (data-calendar ,(base64encode (or (prop (parent ev) 'NAME) "unknown"))) - (data-uid ,(prop ev 'UID)) + (data-uid ,(output-uid ev)) (class "vevent event" ,(when (and (prop ev 'PARTSTAT) @@ -470,6 +471,30 @@ (else (->string value)))))) (prop event 'RRULE))))) + +;; Return a unique identifier for a specific instance of an event. +;; Allows us to reference each instance of a repeating event separately +;; from any other +(define-public (output-uid event) + (string-concatenate + (cons + (prop event 'UID) + (when (repeating? event) + ;; TODO this will break if a UID already looks like this... + ;; Just using a pre-generated unique string would solve it, + ;; until someone wants to break us. Therefore, we just give + ;; up for now, until a proper solution can be devised. + (list "---" + ;; TODO Will this give us a unique identifier? + ;; Or can two events share UID along with start time + (datetime->string + (as-datetime (or + ;; TODO What happens if the parameter RANGE=THISANDFUTURE is set? + (prop event 'RECURRENCE-ID) + (prop event 'DTSTART))) + "~Y-~m-~dT~H:~M:~S")))))) + + ;; TODO bind this into the xcal (define (editable-repeat-info event) (warning "editable-repeat-info is deprecated") diff --git a/module/calp/html/view/calendar.scm b/module/calp/html/view/calendar.scm index 45309856..b5319ea7 100644 --- a/module/calp/html/view/calendar.scm +++ b/module/calp/html/view/calendar.scm @@ -13,6 +13,7 @@ fmt-day make-block fmt-single-event + output-uid )) :use-module (calp html config) :use-module (calp html util) @@ -25,6 +26,7 @@ :use-module (srfi srfi-41) :use-module (srfi srfi-41 util) + :use-module ((vcomponent recurrence) :select (repeating? generate-recurrence-set)) :use-module ((vcomponent group) :select (group-stream get-groups-between)) :use-module ((base64) :select (base64encode)) @@ -361,26 +363,37 @@ window.default_calendar='~a';" SEQUENCE REQUEST-STATUS ))) - ;; (div (@ (style "display:none !important;")) - ;; ,(map (lambda (calendar) - ;; (prop calendar 'NAME)) - ;; calendars)) - - ,@(let ((flat-events - ;; A simple filter-sorted-stream on event-overlaps? here fails. - ;; See tests/annoying-events.scm - (stream->list - (stream-filter - (lambda (ev) - ((@ (vcomponent datetime) event-overlaps?) - ev start-date - (date+ end-date (date day: 1)))) - (stream-take-while (lambda (ev) (date< - (as-date (prop ev 'DTSTART)) - (date+ end-date (date day: 1)))) - events))))) - - `((div (@ (style "display:none !important;") + ,@(let* ( + (flat-events + ;; A simple filter-sorted-stream on event-overlaps? here fails. + ;; See tests/annoying-events.scm + (stream->list + (stream-filter + (lambda (ev) + ((@ (vcomponent datetime) event-overlaps?) + ev start-date + (date+ end-date (date day: 1)))) + (stream-take-while (lambda (ev) (date< + (as-date (prop ev 'DTSTART)) + (date+ end-date (date day: 1)))) + events)))) + (repeating% regular (partition repeating? flat-events)) + (repeating + (for ev in repeating% + (define instance (copy-vcomponent ev)) + + (set! (prop instance 'UID) (output-uid instance)) + (delete-parameter! (prop* instance 'DTSTART) '-X-HNH-ORIGINAL) + (delete-parameter! (prop* instance 'DTEND) '-X-HNH-ORIGINAL) + + instance))) + + `( + ;; Mapping showing which events belongs to which calendar, + ;; on the form + ;; (calendar (@ (key ,(base64-encode calendar-name))) + ;; (li ,event-uid) ...) + (div (@ (style "display:none !important;") (id "calendar-event-mapping")) ,(let ((ht (make-hash-table))) (for-each (lambda (event) @@ -388,7 +401,8 @@ window.default_calendar='~a';" (hash-set! ht name (cons (prop event 'UID) (hash-ref ht name '())))) - flat-events) + (append regular repeating)) + (hash-map->list (lambda (key values) `(calendar (@ (key ,(base64encode key))) @@ -399,8 +413,7 @@ window.default_calendar='~a';" ;; Calendar data for all events in current interval, ;; rendered as xcal. (div (@ (style "display:none !important;") - (id "xcal-data")) - ,((@ (vcomponent xcal output) ns-wrap) - (map (@ (vcomponent xcal output) vcomponent->sxcal) - flat-events - )))))))) + (id "xcal-data")) + ,((@ (vcomponent xcal output) ns-wrap) + (map (@ (vcomponent xcal output) vcomponent->sxcal) + (append regular repeating))))))))) diff --git a/module/calp/html/view/calendar/week.scm b/module/calp/html/view/calendar/week.scm index 6df51da2..d6f35ad8 100644 --- a/module/calp/html/view/calendar/week.scm +++ b/module/calp/html/view/calendar/week.scm @@ -14,7 +14,7 @@ event-zero-length? events-between)) :use-module ((calp html vcomponent) - :select (make-block) ) + :select (make-block output-uid) ) ;; :use-module ((calp html components) ;; :select ()) :use-module ((vcomponent group) @@ -56,15 +56,8 @@ ,@(for event in (stream->list (events-between start-date end-date events)) `(popup-element - ;; TODO (@ (class "vevent") - (data-uid ,(prop event 'UID))) - ) - #; - ((@ (calp html vcomponent ) popup) ; - event (string-append "popup" (html-id event)))) - - )) + (data-uid ,(output-uid event))))))) ;; description in sidebar / tab of popup (template (@ (id "vevent-description")) diff --git a/static/components/edit-rrule.ts b/static/components/edit-rrule.ts index 6be01b76..cac19e80 100644 --- a/static/components/edit-rrule.ts +++ b/static/components/edit-rrule.ts @@ -17,6 +17,24 @@ class EditRRule extends ComponentVEvent { let frag = this.template.content.cloneNode(true) as DocumentFragment let body = frag.firstElementChild! this.replaceChildren(body); + + for (let el of this.querySelectorAll('[name]')) { + el.addEventListener('input', () => { + // console.log(this); + let data = vcal_objects.get(this.uid)!; + let rrule = data.getProperty('rrule') + if (!rrule) { + console.warn('RRUle missing from object'); + return; + } + rrule = rrule as RecurrenceRule + + console.log(el.getAttribute('name'), (el as any).value); + rrule[el.getAttribute('name')!] = (el as any).value; + data.setProperty('rrule', rrule); + + }); + } } connectedCallback() { diff --git a/static/components/vevent-edit.ts b/static/components/vevent-edit.ts index d48c7967..5c482882 100644 --- a/static/components/vevent-edit.ts +++ b/static/components/vevent-edit.ts @@ -7,6 +7,7 @@ import { DateTimeInput } from './date-time-input' import { vcal_objects } from '../globals' import { VEvent, RecurrenceRule } from '../vevent' import { create_event } from '../server_connect' +import { to_boolean } from '../lib' /* <vevent-edit /> Edit form for a given VEvent. Used as the edit tab of popups. @@ -148,6 +149,11 @@ class ComponentEdit extends ComponentVEvent { } } + let el = this.querySelector('[name="has_repeats"]') + if (el) { + (el as HTMLInputElement).checked = to_boolean(data.getProperty('rrule')) + } + if (data.calendar) { for (let el of this.getElementsByClassName('calendar-selection')) { (el as HTMLSelectElement).value = data.calendar; diff --git a/static/jcal.ts b/static/jcal.ts index 605f41e7..41f33db4 100644 --- a/static/jcal.ts +++ b/static/jcal.ts @@ -33,9 +33,17 @@ function jcal_type_to_xcal(doc: Document, type: ical_type, value: any): Element case 'recur': for (var key in value) { if (!value.hasOwnProperty(key)) continue; - let e = doc.createElementNS(xcal, key); - e.textContent = value[key]; - el.appendChild(e); + if (key === 'byday') { + for (let v of value[key]) { + let e = doc.createElementNS(xcal, key); + e.textContent = v; + el.appendChild(e); + } + } else { + let e = doc.createElementNS(xcal, key); + e.textContent = value[key]; + el.appendChild(e); + } } break; 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': |