aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--module/calp/html/vcomponent.scm27
-rw-r--r--module/calp/html/view/calendar.scm65
-rw-r--r--module/calp/html/view/calendar/week.scm11
-rw-r--r--static/components/edit-rrule.ts18
-rw-r--r--static/components/vevent-edit.ts6
-rw-r--r--static/jcal.ts14
-rw-r--r--static/vevent.ts2
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':