aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-09-05 11:41:46 +0200
committerHugo Hörnquist <hugo@lysator.liu.se>2023-09-05 11:41:46 +0200
commitf653a01328be3b8be6af35c0c96867623765ca5b (patch)
treeaee9a5d3abfc39270f55defd7bc1a7e47920ffc3
parentMinor whitespace cleanup. (diff)
downloadcalp-f653a01328be3b8be6af35c0c96867623765ca5b.tar.gz
calp-f653a01328be3b8be6af35c0c96867623765ca5b.tar.xz
Move JS documentation into the JS-code.
Texinfo was a bad match for how TypeScript is structured. This also allows generation of jsdoc pages, which can be nice. Another large win is that this opens up for the texinfo pages to replace the Guile heading with different subheadings, including - external library - internal library - C library - ...
-rw-r--r--doc/ref/calp.texi4
-rw-r--r--doc/ref/guile/util-exceptions.texi22
-rw-r--r--doc/ref/javascript.texi48
-rw-r--r--doc/ref/javascript/clock.texi78
-rw-r--r--doc/ref/javascript/components/changelog.texi10
-rw-r--r--doc/ref/javascript/components/date_time_input.texi34
-rw-r--r--doc/ref/javascript/components/edit_rrule.texi10
-rw-r--r--doc/ref/javascript/components/input_list.texi16
-rw-r--r--doc/ref/javascript/components/popup_element.texi40
-rw-r--r--doc/ref/javascript/components/tab_group_element.texi46
-rw-r--r--doc/ref/javascript/components/vevent.texi23
-rw-r--r--doc/ref/javascript/components/vevent_block.texi10
-rw-r--r--doc/ref/javascript/components/vevent_description.texi16
-rw-r--r--doc/ref/javascript/components/vevent_dl.texi11
-rw-r--r--doc/ref/javascript/components/vevent_edit.texi9
-rw-r--r--doc/ref/javascript/eventCreator.texi15
-rw-r--r--doc/ref/javascript/formatters.texi23
-rw-r--r--doc/ref/javascript/globals.texi41
-rw-r--r--doc/ref/javascript/jcal.texi7
-rw-r--r--doc/ref/javascript/lib.texi148
-rw-r--r--doc/ref/javascript/server_connect.texi22
-rw-r--r--doc/ref/javascript/types.texi95
-rw-r--r--doc/ref/javascript/user-additions.texi18
-rw-r--r--doc/ref/javascript/vevent.texi113
-rw-r--r--static/README.md36
-rw-r--r--static/package-lock.json34
-rw-r--r--static/package.json1
-rw-r--r--static/ts/clock.ts44
-rw-r--r--static/ts/components.ts9
-rw-r--r--static/ts/components/changelog.ts11
-rw-r--r--static/ts/components/date-time-input.ts32
-rw-r--r--static/ts/components/edit-rrule.ts12
-rw-r--r--static/ts/components/input-list.ts14
-rw-r--r--static/ts/components/popup-element.ts40
-rw-r--r--static/ts/components/tab-group-element.ts49
-rw-r--r--static/ts/components/vevent-block.ts11
-rw-r--r--static/ts/components/vevent-description.ts16
-rw-r--r--static/ts/components/vevent-dl.ts12
-rw-r--r--static/ts/components/vevent-edit.ts11
-rw-r--r--static/ts/components/vevent.ts27
-rw-r--r--static/ts/formatters.ts20
-rw-r--r--static/ts/globals.ts31
-rw-r--r--static/ts/jcal.ts4
-rw-r--r--static/ts/lib.ts136
-rw-r--r--static/ts/server_connect.ts22
-rw-r--r--static/ts/types.ts48
-rw-r--r--static/ts/vevent.ts61
-rw-r--r--static/tsconfig.json12
48 files changed, 684 insertions, 868 deletions
diff --git a/doc/ref/calp.texi b/doc/ref/calp.texi
index 92c30242..4dac681b 100644
--- a/doc/ref/calp.texi
+++ b/doc/ref/calp.texi
@@ -64,7 +64,6 @@ text @footnote{Improvements welcome}
@c @end menu
@include guile.texi
-@include javascript.texi
@node Index
@unnumbered Index
@@ -75,7 +74,4 @@ text @footnote{Improvements welcome}
@printindex tp
@printindex vr
-@unnumbered Web Components
-@printindex wc
-
@bye
diff --git a/doc/ref/guile/util-exceptions.texi b/doc/ref/guile/util-exceptions.texi
new file mode 100644
index 00000000..4e84d8c4
--- /dev/null
+++ b/doc/ref/guile/util-exceptions.texi
@@ -0,0 +1,22 @@
+@node Exception Utilities
+@section Exception Utilities
+
+@defun warning fmt args ...
+
+@end defun
+
+@deftp {parameter} warning-handler
+Procedure, which htnaoe htn oeu htn oeu
+@end deftp
+
+@deftp {parameter} warnings-are-errors
+Boolean parameter
+@end deftp
+
+@defun fatal fmt args ...
+Display the message in fmt, populated with args, then raises the UNIX
+signal 2, which kills the program.
+@end defun
+
+@defun filter-stack pred? stack
+@end defun
diff --git a/doc/ref/javascript.texi b/doc/ref/javascript.texi
deleted file mode 100644
index bbe1cb25..00000000
--- a/doc/ref/javascript.texi
+++ /dev/null
@@ -1,48 +0,0 @@
-@node Javascript
-@chapter Javascript
-
-@c web components
-@defindex wc
-
-@c done
-@node General Stuff
-@section General stuff
-The frontend code has its entry-point in @code{script.ts}
-
-All elements are initialized in elements.ts
-
-@include javascript/clock.texi
-@include javascript/lib.texi
-@include javascript/eventCreator.texi
-@include javascript/types.texi
-@include javascript/vevent.texi
-@include javascript/globals.texi
-@include javascript/server_connect.texi
-@include javascript/formatters.texi
-@include javascript/user-additions.texi
-
-@node General Components
-@section General Components
-@include javascript/components/date_time_input.texi
-@include javascript/components/input_list.texi
-
-@node VEvent Components
-@section VEvent Components
-@include javascript/components/vevent.texi
-@include javascript/components/changelog.texi
-@include javascript/components/edit_rrule.texi
-@include javascript/components/popup_element.texi
-@include javascript/components/tab_group_element.texi
-@include javascript/components/vevent_block.texi
-@include javascript/components/vevent_description.texi
-@include javascript/components/vevent_dl.texi
-@include javascript/components/vevent_edit.texi
-
-@section About our buildsystem
-Currently (almost) everything is written in Typescript, and bundled
-through browserify. Ideally we would, for debug builds, export the
-single transplied Javascript files, but Chromium Chromium lacks
-support for modules on XHTML documents
-@url{https://bugs.chromium.org/p/chromium/issues/detail?id=717643}.
-However, seeing as the issue still gets frequent updates as of 2021 I
-believe that this might one day get resolved.
diff --git a/doc/ref/javascript/clock.texi b/doc/ref/javascript/clock.texi
deleted file mode 100644
index 10ab7d4e..00000000
--- a/doc/ref/javascript/clock.texi
+++ /dev/null
@@ -1,78 +0,0 @@
-@node clock
-@subsection clock.js
-
-@deftp {abstract class} Clock
-Interface for ``things'' which wants to get updated on a human timescale.
-
-@defmethod Clock update now
-@c abstract method
-Called every now and then, with @var{now} being the current time.
-@end defmethod
-@end deftp
-
-@deftp {class} Timebar @extends{Clock}
-The (blue) vertical line which show the current time in the current day.
-
-@c @defmethod Timebar constructor ∅
-@c @end defmethod
-@c
-@c @defmethod Timebar update now
-@c @end defmethod
-@end deftp
-
-@deftp {class} SmallcalCellHighlight @extends{Clock}
-Highlights the current date in the small calendar to the side.
-Currently directly sets a border
-@TODO{but should preferably set a class instead}.
-
-@defmethod SmallcalCellHighlight constructor small_cal
-@var{small_cal} is the DOM-node of the calendar.
-(it should support querySelector).
-@end defmethod
-
-@c @defmethod SmallcalCellHighlight update now
-@c @end defmethod
-@end deftp
-
-@deftp {class} ButtonUpdater @extends{Clock}
-Updates the ``Today'' link in the side panel to point directly to the
-correct web-address. The link works without JavaScript, but then
-requires a redirect from the server.
-
-All actual updating logic is already abstracted away. It would be
-desirable if something more was done with this.
-
-@defmethod ButtonUpdater el proc
-Takes the element @var{el} to be updated, and the procedure @var{proc}
-which will be called with the element, and the current time.
-@end defmethod
-@end deftp
-
-
-As of commit
-@githash{c9719ce7937f0f0f2aa371ced1d585f67af22457,static/script.js,231}
-all objects required manual setup. See static/script.js:
-
-@verbatim
- 231 let start_time = document.querySelector("meta[name='start-time']").content;
- 232 let end_time = document.querySelector("meta[name='end-time']").content;
- 233
- 234 const button_updater = new ButtonUpdater(
- 235 document.getElementById("today-button"),
- 236 (e, d) => e.href = d.format('~Y-~m-~d') + ".html"
- 237 );
- 238
- 239 const sch = new SmallcalCellHighlight(
- 240 document.querySelector('.small-calendar'))
- 241
- 242 const timebar = new Timebar(start_time, end_time);
- 243
- 244 timebar.update(new Date);
- 245 window.setInterval(() => {
- 246 let d = new Date;
- 247 timebar.update(d);
- 248 button_updater.update(d);
- 249 sch.update(d);
- 250 }, 1000 * 60);
- 251
-@end verbatim
diff --git a/doc/ref/javascript/components/changelog.texi b/doc/ref/javascript/components/changelog.texi
deleted file mode 100644
index d14fb84e..00000000
--- a/doc/ref/javascript/components/changelog.texi
+++ /dev/null
@@ -1,10 +0,0 @@
-@subsection Changelog
-
-@deftp {Web Component for VEvent} VEventChangelog
-@wcindex <vevent-changelog>
-@wcindex vevent-changelog
-@anchor{VEventChangelog}
-@code{<vevent-changelog>}
-
-Display of a VEvents changelog. @ref{ChangeLogEntry}
-@end deftp
diff --git a/doc/ref/javascript/components/date_time_input.texi b/doc/ref/javascript/components/date_time_input.texi
deleted file mode 100644
index f26627d2..00000000
--- a/doc/ref/javascript/components/date_time_input.texi
+++ /dev/null
@@ -1,34 +0,0 @@
-@subsection date-time-input
-
-@deftp {Web Component} DateTimeInput
-@wcindex <date-time-input>
-@wcindex date-time-input
-@code {<date-time-input>}
-
-An element for input for date-times. Similar to
-@example
-<input type="date"/>
-<input type="time"/>
-@end example
-But as a single unit.
-
-@deftypeivar DateTimeInput boolean dateonly
-Setting this to true disabled the time part of the input, and makes
-any output only have date components (alternativly, the time component
-set to zero).
-@end deftypeivar
-
-@defcv {Attribute} DateTimeInput dateonly
-Same data as the field dateonly, but as an attribute. Present means
-true, absent means false.
-@end defcv
-
-@deftypeivar DateTimeInput Date value
-Returns current value as a Date object.
-@end deftypeivar
-
-@deftypeivar DateTimeInput string stringValue
-Returns current value as an ISO-8601 formatted string.
-@end deftypeivar
-
-@end deftp
diff --git a/doc/ref/javascript/components/edit_rrule.texi b/doc/ref/javascript/components/edit_rrule.texi
deleted file mode 100644
index 21437863..00000000
--- a/doc/ref/javascript/components/edit_rrule.texi
+++ /dev/null
@@ -1,10 +0,0 @@
-@subsection Edit RRule
-
-@deftp {Web Component for VEvent} EditRRule
-@wcindex <vevent-edit-rrule>
-@wcindex vevent-edit-rrule
-@code{<vevent-edit-rrule>}
-
-An edit form for a recurrence rule. Searches its template for elements
-with @code{[name="<<field name>>"]}, and binds to those.
-@end deftp
diff --git a/doc/ref/javascript/components/input_list.texi b/doc/ref/javascript/components/input_list.texi
deleted file mode 100644
index bdc00ecb..00000000
--- a/doc/ref/javascript/components/input_list.texi
+++ /dev/null
@@ -1,16 +0,0 @@
-@subsection input_list.js
-
-@deftp {Web Component} InputList
-@wcindex <input-list>
-@wcindex input-list
-@code{<input-list>}
-
-A list of identical input fields, which forms a group. For example
-useful to handle keywords.
-
-@deftypeivar DateTimeInput {any[]} value
-The value from each element, except the last which should always be empty.
-Has an unspecified type, since children:s value field might give non-strings.
-@end deftypeivar
-
-@end deftp
diff --git a/doc/ref/javascript/components/popup_element.texi b/doc/ref/javascript/components/popup_element.texi
deleted file mode 100644
index 2b76b347..00000000
--- a/doc/ref/javascript/components/popup_element.texi
+++ /dev/null
@@ -1,40 +0,0 @@
-@subsection Popup
-
-@deftp {Web Component for VEvent} PopupElement
-@wcindex <popup-element>
-@wcindex popup-element
-@code{<popup-element>}
-
-A (small) floating window containing information, which can be dragged
-arround. Consists of a navigation bar with a few buttons for
-controlling the window, which also works as a drag handle, along with
-an area for contents, which can be resized by the user.
-
-Currently tightly coupled to VEvent's, since their color
-profile is derived from their owning events calendar, and they have
-action buttons for the event in their navigation bar.
-
-@deftypecv {Static Member} PopupElement {PopupElement?} activePopup
-The popup which was most recently interacted with by the user. Used to
-move it on top of all others, as well as sending relevant key events there.
-@end deftypecv
-
-@defcv {Attribute} PopupElement visible
-Present is the popup is currently visible, absent otherwise.
-@end defcv
-
-@deftypeivar PopupElement boolean visible
-See the attribute of the same name.
-@end deftypeivar
-
-@defmethod PopupElement maximize
-Resize the popup window to fill the current viewport (mostly). Is
-probably bonud to the maximize button in the navigation bar.
-@end defmethod
-@end deftp
-
-@deftypefun PopupElement setup_popup_element VEvent
-Create a new popup element for the given VEvent, and ready it for
-editing the event. Used when creating event (through the frontend).
-The return value can safely be ignored.
-@end deftypefun
diff --git a/doc/ref/javascript/components/tab_group_element.texi b/doc/ref/javascript/components/tab_group_element.texi
deleted file mode 100644
index 7e0b190a..00000000
--- a/doc/ref/javascript/components/tab_group_element.texi
+++ /dev/null
@@ -1,46 +0,0 @@
-@subsection Tab Group Element
-
-@deftp {Web Component for VEvent} TabGroupElement
-@wcindex <tab-group>
-@wcindex tab-group
-@code{<tab-group>}
-
-A group of tabs, where only one can be visible at a time.
-
-@c TODO which form does the HTML document have? For CSS purposes
-
-Each tab consists of two parts, a label which is used for selecting
-it, and a tab-element, which contains the actual content. These two
-should refer to each other as follows:
-
-@example
-+---------------+ +-----------------+
-| TabLabel | | Tab |
-+---------------+ +-----------------+
-| id |<----| aria-labelledby |
-| aria-controls |---->| id |
-+---------------+ +-----------------+
-@end example
-
-Further information about tabs in HTML can be found here:
-@url{https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role}
-
-@defvr {CSS Variable} {--tabcount}
-Each tab element has the style property @code{--tabcount} set to how
-many tabs it has. This is mostly useful to make sure the tab context
-is large enough to fit all tab labels without overflowing.
-@end defvr
-
-@deftypemethod TabGroupElement void addTab {HTMLElement} {label: string?} {title: string?}
-Adds a new tab to the group. The first parameter will make up the body
-of the tab. The label is whath should be shown in the tab selector,
-but defaults to the first letter of the text content of the body node.
-Title is the hoover text of the label.
-@end deftypemethod
-
-@deftypemethod TabGroupElement void removeTab {HTMLElement}
-HTMLElement must be one of the tab bodies in this group. This method
-removes it, along with its TabLabel.
-@end deftypemethod
-
-@end deftp
diff --git a/doc/ref/javascript/components/vevent.texi b/doc/ref/javascript/components/vevent.texi
deleted file mode 100644
index be53a46e..00000000
--- a/doc/ref/javascript/components/vevent.texi
+++ /dev/null
@@ -1,23 +0,0 @@
-@subsection vevent
-
-@deftp {Abstract Web Component} ComponentVEvent {uid: string?}
-
-@c TODO what is done in the default constructor,
-@c and the default connectedCallback
-
-This registeres itself, but doesn't redraw
-We do however redraw in connectedCallback
-
-@deftypeivar ComponentVEvent uid uid
-@end deftypeivar
-
-@deftypeivar ComponentVEvent {HTMLTemplateElement?} template
-@end deftypeivar
-
-@deftypemethod ComponentVEvent void redraw (data: VEvent)
-While abstract for this, @emph{must} be overridden for everyone else
-@end deftypemethod
-@end deftp
-
-Note that many of these assume that their initial children are
-configured specifically, that is however not completely documented.
diff --git a/doc/ref/javascript/components/vevent_block.texi b/doc/ref/javascript/components/vevent_block.texi
deleted file mode 100644
index 1a0ef160..00000000
--- a/doc/ref/javascript/components/vevent_block.texi
+++ /dev/null
@@ -1,10 +0,0 @@
-@subsection VEvent Block
-
-@deftp {Web Component for VEvent} ComponentBlock
-@wcindex <vevent-block>
-@wcindex vevent-block
-@code{<vevent-block>}
-A block in our graphical view.
-
-Unique in that it works quite differently between the week and month view.
-@end deftp
diff --git a/doc/ref/javascript/components/vevent_description.texi b/doc/ref/javascript/components/vevent_description.texi
deleted file mode 100644
index 54dda7e3..00000000
--- a/doc/ref/javascript/components/vevent_description.texi
+++ /dev/null
@@ -1,16 +0,0 @@
-@subsection VEvent Description
-
-@deftp {Web Component for VEvent} ComponentDescription
-@wcindex <vevent-description>
-@wcindex vevent-description
-@code{<vevent-description>}
-
-A text representation of a VEvent. Used as the summary tab of our
-popup windows, and in the sidebar.
-
-When redrawn, it looks for an HTML-tag inside its template having the
-attribute @code{data-property} matching the properties name. If one is
-found, it looks in the @code{formatters} table
-(@ref{formatters-proc}), for a field matching the property value, and
-defaults to the key @code{default}.
-@end deftp
diff --git a/doc/ref/javascript/components/vevent_dl.texi b/doc/ref/javascript/components/vevent_dl.texi
deleted file mode 100644
index 26bc8fd4..00000000
--- a/doc/ref/javascript/components/vevent_dl.texi
+++ /dev/null
@@ -1,11 +0,0 @@
-@subsection VEvent Description List
-
-@deftp {Web Component for VEvent} VEventDL
-@wcindex <vevent-dl>
-@wcindex vevent-dl
-@code{<vevent-dl>}
-A description list of a vevent, used for debugging.
-
-No guarantees are given about the contents of the data fields, more
-than that they are related to the value in question.
-@end deftp
diff --git a/doc/ref/javascript/components/vevent_edit.texi b/doc/ref/javascript/components/vevent_edit.texi
deleted file mode 100644
index 67e9f6b3..00000000
--- a/doc/ref/javascript/components/vevent_edit.texi
+++ /dev/null
@@ -1,9 +0,0 @@
-@subsection VEvent Edit
-
-@deftp {Web Component for VEvent} ComponentEdit
-@wcindex <vevent-edit>
-@wcindex vevent-edit
-@code{<vevent-edit>}
-Edit form for a vevent, designed for useful human interaction (and
-thereby not being all-encompassing).
-@end deftp
diff --git a/doc/ref/javascript/eventCreator.texi b/doc/ref/javascript/eventCreator.texi
deleted file mode 100644
index 164d1335..00000000
--- a/doc/ref/javascript/eventCreator.texi
+++ /dev/null
@@ -1,15 +0,0 @@
-@deftp {class} EventCreator
-
-@defmethod EventCreator create_empty_event
-@end defmethod
-
-@defmethod EventCreator create_event_down intended_target
-@end defmethod
-
-@defmethod EventCreator create_event_move pos_in [round=1] [wide_element=false]
-@end defmethod
-
-@defmethod EventCreator create_event_finisher callback
-@end defmethod
-
-@end deftp
diff --git a/doc/ref/javascript/formatters.texi b/doc/ref/javascript/formatters.texi
deleted file mode 100644
index a3086aa9..00000000
--- a/doc/ref/javascript/formatters.texi
+++ /dev/null
@@ -1,23 +0,0 @@
-@node formatters
-@subsection formatters
-
-Formatting procedures used by some components.
-@c TODO can we have a backref of every node containing @ref{formatters-proc}?
-
-@deftypefun void format(targetElement:HTMLElement, data:VEvent, key:string)
-Checks if a specific formatter exists for the given key, and executes
-it.
-Defaults to 'default', and also runs that if the regular formatter throws.
-@end deftypefun
-
-@deftypevar {Map<string, (e:HTMLElement, d:VEvent, s:any) => void>} formatters
-@anchor{formatters-proc}
-
-Each procedure takes three arguments. The HTML-element which contents
-should be replaced, the VEvent containing all data, and the target
-value, as returned by @ref{VEvent.getProperty}.
-@end deftypevar
-
-@deftypevr {Window Value} {Map<string, (e:HTMLElement, d:VEvent, s:string) => void>} formatters
-Same object as @xref{formatters-proc}. Provided for @xref{user-additions.js}.
-@end deftypevr
diff --git a/doc/ref/javascript/globals.texi b/doc/ref/javascript/globals.texi
deleted file mode 100644
index 5ef7a43b..00000000
--- a/doc/ref/javascript/globals.texi
+++ /dev/null
@@ -1,41 +0,0 @@
-@node globals
-@subsection globals.ts
-
-Different variables and values which for different reasons needs to be
-global. Window Value's are those that are bound to the @code{window}
-context in JavaScript, so is really always available, no opt out.
-
-@deftypevar {Map<uid, VEvent>} vcal_objects
-All VEvent objects on current page, indexed by their unique identifiers.
-
-A global object store.
-@end deftypevar
-
-@deftypevar {Map<uid, string>} event_calendar_mapping
-Mapping from VEvent unique identifier, to name of its calendar. Should
-probably not be global, so refrain from using it.
-@end deftypevar
-
-@deftypevr {Window Value} {Map<uid, VEvent>} vcal_objects
-The exact same object store as the regular variable of the same
-name. Mostly here for human debugability.
-@end deftypevr
-
-@deftypevr {Window Value} {@code{'month'} | @code{'string'}} VIEW
-How the calendar is currently formatted. Should be set by the backend
-through a simple @code{script}-tag.
-@end deftypevr
-
-@deftypevr {Window Value} {boolean} EDIT_MODE
-However editing of events is enabled or not.
-Should be set by the backend through a simple @code{script}-tag.
-@end deftypevr
-
-@deftypevr {Window Value} {string} default_calendar
-Name of the calendar to assume when creating new events.
-Should be set by the backend through a simple @code{script}-tag.
-@end deftypevr
-
-@c TODO addNewEvent
-@c @deftypevr {Window Value} {string} default_calendar
-@c @end deftypevr
diff --git a/doc/ref/javascript/jcal.texi b/doc/ref/javascript/jcal.texi
deleted file mode 100644
index 997b4d59..00000000
--- a/doc/ref/javascript/jcal.texi
+++ /dev/null
@@ -1,7 +0,0 @@
-@node jcal
-@subsection jcal.js
-
-@deftypefun Document jcal_to_xcal {JCal ...}
-A document with the xcal namespace, and @code{icalendar} as its root
-element. Each child is a valid xcal representation of our JCal object.
-@end deftypefun
diff --git a/doc/ref/javascript/lib.texi b/doc/ref/javascript/lib.texi
deleted file mode 100644
index a3fb0697..00000000
--- a/doc/ref/javascript/lib.texi
+++ /dev/null
@@ -1,148 +0,0 @@
-
-@node lib
-@subsection lib.js
-
-General procedures which in theory could be used anywhere.
-
-
-@node Default prototype extensions
-@subsubsection Default prototype extensions
-
-HTMLElement extensions
-
-@defmethod HTMLElement addEventListener name proc
-Replace the default @code{addEventListener} with a version that stores
-all listeners in the dictionary @var{listeners}.
-@end defmethod
-
-@defivar HTMLElement listeners
-Dictionary of all registered listeners to this element.
-Keys are taken from @code{addEventListener}.
-@end defivar
-
-@defmethod DOMTokenList find regexp
-Finds the first element of the DOMTokenList whichs value matches
-the supplied regexp. Returns a pair of the index and the value.
-@end defmethod
-
-@defmethod Object format args ...
-Returns a string representation of the given object.
-Allows extending for custom types,
-@ref{date-format}
-@end defmethod
-
-@node General
-@subsubsection General
-
-@defun zip args ...
-Takes a list of lists, and returns a single list of tuples.
-@example
-» zip([1,2,3,4,5], "Hello")
-← [[1,'H'],[2,'e'],[3,'l'],[4,'l'],[5,'o']]
-@end example
-@end defun
-
-@defun makeElement name [attr=@{@}]
-Creates a new DOM element of type @var{name}, with all keys in
-@var{attr} transfered to it. For example, the equivalent of
-@example
-<input type='number'/>
-@end example
-would be
-@verbatim
-values.push(makeElement('input', {
- type: 'number',
-}));
-@end verbatim
-.
-@end defun
-
-@defun round_time time fraction
-TODO
-@end defun
-
-@defun date_to_percent date
-Retuns how far along the date specified by @var{date} is, between 0
-and 100, where 00:00 maps to 0, and 23:59 to ~100.
-@end defun
-
-@defun gensym [pxrefix='gensym']
-Generates a new string which is (hopefully) globally unique.
-Compare with @code{gensym} from Lisp.
-@end defun
-
-@defun asList thing
-Ensures that @var{thing} is a list. Returning it outright if it
-already is one, otherwise wrapping it in a list.
-@end defun
-
-@node Date
-@subsubsection Date
-
-Some extensions to the builtin class ``Date'' is made.
-
-@defivar Date utc
-Boolean indicating if the given timestamp is in UTC or local time.
-true means UTC.
-@end defivar
-
-@defivar Date dateonly
-Boolean indicating if the time component of the Date object should be disregarded.
-@end defivar
-
-@defun parseDate str
-Takes a string @var{str}, which should be in ISO-8601 date-format, and
-returns a javascript Date object.
-Handles date-times, with and without seconds, trailing `Z' for
-time-zones, and dates without times.
-If no time is given the @code{dateonly} attribute is set to yes.
-@end defun
-
-@defun copyDate date
-Creates a new instance of the given Date @var{date}, also transfers my
-custom fields.
-@end defun
-
-@defun to_local date
-@anchor{to_local}
-Returns a Date object (which may be new) which is guaranteed in local
-time.
-This means that the @var{utc} field is @code{false}, and that
-@code{to_local(current_time())} should show what your wall-clock shows.
-@end defun
-
-@defmethod Date format str args ...
-@anchor{date-format}
-Formats a Date object according to the format specification @var{str}.
-Keeping with Guile each format specifier starts with a ~.
-
-@table @samp
-@item ~~
-literal ~
-@c Almost all fields are left padded. How do I signify this
-@c with a single footnote?
-@item ~Y
-year, left-padding with zeroes.
-@item ~m
-month number, left padded with zeroes.
-@item ~d
-day of month.
-@item ~H
-hour
-@item ~M
-minute
-@item ~S
-second
-@item ~Z
-'Z' if Date is UTC, otherwise nothing
-@item ~L
-Converts the date to local time
-(@pxref{to_local}) (doesn't modify source object). Outputs nothing
-@end table
-@end defmethod
-
-@defun format_date date str
-Equivalent to @code{(@var{date}).format(@var{str})}.
-@c TODO link
-@end defun
-
diff --git a/doc/ref/javascript/server_connect.texi b/doc/ref/javascript/server_connect.texi
deleted file mode 100644
index c67f47ff..00000000
--- a/doc/ref/javascript/server_connect.texi
+++ /dev/null
@@ -1,22 +0,0 @@
-@node server_connect
-@subsection server_connect.js
-
-Procedures for interfacing with the backend server.
-
-@deftypefn {Async Function} void create_event {event: VEvent}
-Packs up the given event and sends it to the server to either be
-created, or simply be updated in the persistant database.
-
-Also does some minor updates registered components, to show that the
-event is actually created.
-@end deftypefn
-
-@deftypefn {Async Function} void remove_event {uid: uid}
-Requests that the server permanently remove the event with the given
-unique id from its persistant storage.
-
-If the server responds with a success also delete it from our local
-store (@code{vcal_objects}).
-
-@c TODO link to our backend flow here
-@end deftypefn
diff --git a/doc/ref/javascript/types.texi b/doc/ref/javascript/types.texi
deleted file mode 100644
index 6f518f53..00000000
--- a/doc/ref/javascript/types.texi
+++ /dev/null
@@ -1,95 +0,0 @@
-@node types
-@subsection types.js
-
-Collection of type information for calendar data.
-
-@defvar all_types
-Name of all valid icalendar types.
-
- text, uri, binary, float, integer, date-time, date, duration,
- period, utc-offset, cal-address, recur, boolean,
-@end defvar
-
-@deftp {Data Type} ical_type
-The union of all elements in @var{all_types}.
-@end deftp
-
-@defvar property_names
-All known names properties (top level keys) can have.
-Such as ``calscale'', ``dtstart'', ...
-@end defvar
-
-@deftypevar {Map<string, string[]>} valid_fields
-Which property fields each component can hold.
-
-@verbatim
-{ 'VCALENDAR': ['PRODID', 'VERSION', 'CALSCALE', 'METHOD'],
- ...
-}
-@end verbatim
-@end deftypevar
-
-@deftypevar {Map<string, Array<ical_type | ical_type[]>>} valid_input_types
-Which types are valid to store under each property.
-If multiple values are an option for that property, then
-the list of possibilities will contain a sub-list (see example).
-
-@verbatim
-{ 'DTSTART': ['date', 'date-time'],
- 'CATEGORIES': [['text']],
- ...
-}
-@end verbatim
-@end deftypevar
-
-@deftp {Data Type} tagname
-Alias of (@code{'vevent'} | @code{'string'}).
-@end deftp
-
-@deftp {Data Type} uid
-Alias of @code{'string'}.
-@end deftp
-
-@c TODO link to the RFC
-@c - RFC 7265 (jCal)
-
-@deftp {Data Type} JCalProperty
-Alias for a record consisting of
-@itemize @bullet
-@item the name of the type, as a string
-@item All parameters of the object, as a @code{Record<string, any>}
-@footnote{Which is simply a regular javascript object, mapping strings to anything}.
-@item An @code{ical_type} value, noting the type of the final field(s)
-@item And one or more values of the type specified by the third field.
-@end itemize
-@end deftp
-
-@deftp {Data Type} JCal
-A record consisting of a @code{tagname}, a list of
-@code{JCalProperties}, and a list of other @code{JCal} objects.
-@end deftp
-
-@defvar xcal
-The xml namespace name for xcalendar, which is
-``urn:ietf:params:xml:ns:icalendar-2.0''.
-@end defvar
-
-
-@deftp {Interface} ChangeLogEntry
-@anchor{ChangeLogEntry}
-
-@ref{VEventChangelog}
-
-@deftypecv {Interface Field} ChangeLogEntry {(@code{'calendar'} | @code{'property'})} type
-@end deftypecv
-
-@deftypecv {Interface Field} ChangeLogEntry {string} name
-@end deftypecv
-
-@deftypecv {Interface Field} ChangeLogEntry {string?} from
-@end deftypecv
-
-@deftypecv {Interface Field} ChangeLogEntry {string?} to
-@end deftypecv
-
-@end deftp
diff --git a/doc/ref/javascript/user-additions.texi b/doc/ref/javascript/user-additions.texi
deleted file mode 100644
index 706b1dd4..00000000
--- a/doc/ref/javascript/user-additions.texi
+++ /dev/null
@@ -1,18 +0,0 @@
-@node user-additions.js
-@section user-additions.js
-
-Some things in the JavaScript code is built to be user-extendable.
-The HTML-page attempts to load @code{/static/user/user-additions.js}.
-
-
-Currently; this only entails @ref{formatters}, where you could, for
-example, parse all HTTP-links in a description.
-
-@example
-window.formatters.set('description', (el, d) => @{
- el.innerHTML = d.replaceAll(/https?:\/\/\S+/g, '<a href="$&">$&</a>');
-@})
-@end example
-
-Remember that the documents are X-HTML, so be @emph{extremely} careful
-with innerHTML.
diff --git a/doc/ref/javascript/vevent.texi b/doc/ref/javascript/vevent.texi
deleted file mode 100644
index 97d15f2a..00000000
--- a/doc/ref/javascript/vevent.texi
+++ /dev/null
@@ -1,113 +0,0 @@
-@node vevent
-@subsection vevent.js
-
-@deftp {Interface} Redrawable
-@deftypeop {Interface Field} Redrawable void redraw VEvent
-@end deftypeop
-@end deftp
-
-@deffn {Type Predicate} isRedrawable element
-Checks if the given element is an instance of Redrawable.
-@end deffn
-
-
-@deftp {class} VEventValue {type: ical_type} {value: any} {parameters: Map<string, any>}
-
-@deftypemethod VEventValue {[Record<string, any>, ical_type, any]} @
- to_jcal {}
-The return value is @emph{almost} a @code{JCalProperty}, just without
-the field name.
-@end deftypemethod
-
-@end deftp
-
-@deftp VEvent {properties: Map<string, VEventValue | VEventValue[]>} @
- {components: VEvent[]}
-
-Component for a single instance of a calendar event. Almost all data
-access should go through @code{getProperty} and @code{setProperty},
-with the exception of the current calendar (which is accessed directly
-through @code{calendar}). Almost all changes through these interfaces
-are logged, and can be viewed through @var{changelog}.
-
-@deftypemethod VEvent {any?} getProperty {key: string}
-@anchor{VEvent.getProperty}
-Returns the value of the given property if set, or undefined otherwise.
-
-For the keys
-@itemize
-@item @code{'CATEGORIES'},
-@item @code{'RESOURCES'},
-@item @code{'FREEBUSY'},
-@item @code{'EXDATE'}, and
-@item @code{'RDATE'}
-@end itemize
-instead returns a list list of values.
-@end deftypemethod
-
-
-@deftypemethod VEvent void setProperty {key: string} {value: any} {type: ical_type?}
-Sets the given property to the given value. If type is given it's
-stored alongside the value, possibly updating what is already
-there. Do however note that no validation between the given type and
-the type of the value is done.
-
-@var{value} may also be a list, but should only be so for the keys
-mentioned in @var{getProperty}.
-
-After the value is set, @var{redraw} is called on all registered
-objects, notifying them of the change.
-@end deftypemethod
-
-@deftypemethod VEvent void setProperties {[string, any, ical_type?][]}
-Equivalent to running @var{setProperty} for each element in the input
-list, but only calls @var{redraw} once at the end.
-@end deftypemethod
-
-@deftypemethod VEvent {IteratableIterator<string>} boundProperties
-Returns an iterator of all our properties.
-@end deftypemethod
-
-@deftypeivar VEvent {ChangeLogEntry[]} {#changelog}
-Every write through getProperty gets logged here, and can be
-consumed. Hopefully this will one day turn into an undo system.
-@ref{ChangeLogEntry}.
-@end deftypeivar
-
-@deftypeivar VEvent {IterableIterator<[number, ChangeLogEntry]>} changelog
-Public (read only) interface to changelog.
-@end deftypeivar
-
-@deftypeivar VEvent {string?} calendar
-The name of the calendar which this event belongs to.
-@end deftypeivar
-
-@deftypemethod VEvent void register {htmlNode: Redrawable}
-Register something redrawable, which will be notified whenever this
-VEvents data is updated.
-@end deftypemethod
-
-@deftypemethod VEvent void unregister {htmlNode: Redrawable}
-Stop recieving redraw events on the given component.
-@end deftypemethod
-
-@deftypemethod VEvent JCal to_jcal
-Converts the object to JCal data.
-@end deftypemethod
-
-@end deftp
-
-
-@deftp {class} RecurrenceRule
-@deftypemethod RecurrenceRule {Record<string, any>} to_jcal
-Converts ourselves to JCal data.
-@end deftypemethod
-@end deftp
-
-@deftypefun RecurrencRule xml_to_recurrence_rule {Element}
-Parse a XCAL recurrence rule into a RecurrenceRule object.
-@end deftypefun
-
-@deftypefun VEvent xml_to_vcal {Element}
-Parse a complete XCAL object into a JS VEvent object.
-@end deftypefun
diff --git a/static/README.md b/static/README.md
index e69de29b..fe5f775c 100644
--- a/static/README.md
+++ b/static/README.md
@@ -0,0 +1,36 @@
+The frontend code has its entry-point in `script.ts`.
+
+## web components
+
+All elements are initialized in components.ts
+
+#### Boolean attributes
+Some components have properties/accessors which also appears as attributes on
+the actuall component (usually with a two-way maping).
+
+For boolean attributes, the attribute is either present or absent.
+
+### General Components
+- `components/date-time-input.ts`
+- `components/input-list.ts`
+
+### VEvent Components
+- `components/vevent.ts`
+- `components/changelog.ts`
+- `components/edit-rrule.ts`
+- `components/popup-element.ts`
+- `components/tab-group-element.ts`
+- `components/vevent-block.ts`
+- `components/vevent-description.ts`
+- `components/vevent-dl.ts`
+- `components/vevent-edit.ts`
+
+## About our buildsystem
+
+Currently (almost) everything is written in Typescript, and bundled
+through browserify. Ideally we would, for debug builds, export the
+single transplied Javascript files, but Chromium Chromium lacks
+support for modules on XHTML documents
+https://bugs.chromium.org/p/chromium/issues/detail?id=717643.
+However, seeing as the issue still gets frequent updates as of 2021 I
+believe that this might one day get resolved.
diff --git a/static/package-lock.json b/static/package-lock.json
index 36521446..c52c00e1 100644
--- a/static/package-lock.json
+++ b/static/package-lock.json
@@ -13,6 +13,7 @@
"uuid": "^8.3.2"
},
"devDependencies": {
+ "@mxssfd/typedoc-theme": "^1.1.2",
"@types/uuid": "^8.3.1"
},
"optionalDependencies": {
@@ -36,6 +37,18 @@
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
"integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug=="
},
+ "node_modules/@mxssfd/typedoc-theme": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@mxssfd/typedoc-theme/-/typedoc-theme-1.1.2.tgz",
+ "integrity": "sha512-Q/9Z+sff8ey92PaB7bnsGOfyNa85vTjyofO8EOH8KwEdfGnV4lGXwLFt4AUth7CCqYplqI9q4JxHNt869mlEcw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 14"
+ },
+ "peerDependencies": {
+ "typedoc": "^0.24.8"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1993,9 +2006,9 @@
}
},
"node_modules/typedoc": {
- "version": "0.24.6",
- "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
- "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
+ "version": "0.24.8",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz",
+ "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==",
"dependencies": {
"lunr": "^2.3.9",
"marked": "^4.3.0",
@@ -2009,7 +2022,7 @@
"node": ">= 14.14"
},
"peerDependencies": {
- "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x"
+ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x"
}
},
"node_modules/typedoc/node_modules/brace-expansion": {
@@ -2129,6 +2142,13 @@
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
"integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug=="
},
+ "@mxssfd/typedoc-theme": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@mxssfd/typedoc-theme/-/typedoc-theme-1.1.2.tgz",
+ "integrity": "sha512-Q/9Z+sff8ey92PaB7bnsGOfyNa85vTjyofO8EOH8KwEdfGnV4lGXwLFt4AUth7CCqYplqI9q4JxHNt869mlEcw==",
+ "dev": true,
+ "requires": {}
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -3515,9 +3535,9 @@
}
},
"typedoc": {
- "version": "0.24.6",
- "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz",
- "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==",
+ "version": "0.24.8",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz",
+ "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==",
"requires": {
"lunr": "^2.3.9",
"marked": "^4.3.0",
diff --git a/static/package.json b/static/package.json
index 46f262f8..f376031d 100644
--- a/static/package.json
+++ b/static/package.json
@@ -3,6 +3,7 @@
"version": "0.1",
"private": true,
"devDependencies": {
+ "@mxssfd/typedoc-theme": "^1.1.2",
"@types/uuid": "^8.3.1"
},
"optionalDependencies": {
diff --git a/static/ts/clock.ts b/static/ts/clock.ts
index bbd15de0..a0e4670a 100644
--- a/static/ts/clock.ts
+++ b/static/ts/clock.ts
@@ -1,3 +1,18 @@
+/**
+ * Components for working with things which depend on the current time.
+ *
+ * Also introduces two web components:
+ *
+ * ```html
+ * <today-button />
+ * <current-time />
+ * ```
+ *
+ * TODO shouldn't these be defined with the rest of the components?
+ *
+ * @module
+ */
+
export {
SmallcalCellHighlight, Timebar,
initialize_clock_components
@@ -5,11 +20,17 @@ export {
import { makeElement, date_to_percent } from './lib'
-abstract class Clock {
+/**
+ * Interface for `things` which wants to get updated on a human timescale.
+ */
+export abstract class Clock {
+ /** Called every now and then
+ * @param now Called with the current time
+ */
abstract update(now: Date): void;
}
-
+/** The (blue) vertical line which show the current time in the current day. */
class Timebar extends Clock {
// start_time: Date
@@ -23,7 +44,6 @@ class Timebar extends Clock {
this.bar_object = null
}
-
update(now: Date) {
// if (! (this.start_time <= now.getTime() && now.getTime() < this.end_time))
// return;
@@ -46,11 +66,21 @@ class Timebar extends Clock {
}
}
+/**
+ * Highlights the current date in the small calendar to the side.
+ * Currently directly sets a border
+ *
+ * @TODO{but should preferably set a class instead}.
+*/
class SmallcalCellHighlight extends Clock {
small_cal: HTMLElement
current_cell: HTMLElement | null
+ /**
+ * @param small_cal the DOM-node of the calendar widget. It must support
+ * querySelector.
+ */
constructor(small_cal: HTMLElement) {
super();
this.small_cal = small_cal;
@@ -103,6 +133,14 @@ class ClockElement extends HTMLElement {
}
+/**
+ * Updates the ``Today'' link in the side panel to point directly to the
+ * correct web-address. The link works without JavaScript, but then
+ * requires a redirect from the server.
+ *
+ * All actual updating logic is already abstracted away. It would be
+ * desirable if something more was done with this.
+ */
class TodayButton extends ClockElement {
a: HTMLAnchorElement;
diff --git a/static/ts/components.ts b/static/ts/components.ts
index 132a9e29..cbd6dc9b 100644
--- a/static/ts/components.ts
+++ b/static/ts/components.ts
@@ -1,3 +1,12 @@
+/**
+ Actuall creation of all web components.
+
+ More text
+
+ @category Web Components
+ @module components
+ */
+
import { ComponentDescription } from './components/vevent-description'
import { ComponentEdit } from './components/vevent-edit'
import { VEventDL } from './components/vevent-dl'
diff --git a/static/ts/components/changelog.ts b/static/ts/components/changelog.ts
index d08f7cb3..720d1656 100644
--- a/static/ts/components/changelog.ts
+++ b/static/ts/components/changelog.ts
@@ -1,3 +1,14 @@
+/**
+ * `<changelog />`
+ *
+ * Display of a VEvents changelog. @ref{ChangeLogEntry}
+ *
+ * @privateRemarks @anchor{VEventChangelog}
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
import { makeElement } from '../lib'
import { ComponentVEvent } from './vevent'
import { VEvent } from '../vevent'
diff --git a/static/ts/components/date-time-input.ts b/static/ts/components/date-time-input.ts
index 20e9a505..d1ab5ba1 100644
--- a/static/ts/components/date-time-input.ts
+++ b/static/ts/components/date-time-input.ts
@@ -1,9 +1,30 @@
+/**
+ * `<date-time-input />`
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
+
export { DateTimeInput }
import { makeElement, parseDate } from '../lib'
-
-/* '<date-time-input />' */
+/**
+ * The HTML component `<date-time-input />`.
+ * An element for input for date-times. Similar to
+ * @example
+ * ```html
+ * <input type="date"/>
+ * <input type="time"/>
+ * ```
+ *
+ * But as a single unit.
+ *
+ * ### Attributes
+ * - dateonly
+ *
+ */
class DateTimeInput extends /* HTMLInputElement */ HTMLElement {
readonly time: HTMLInputElement;
@@ -54,6 +75,11 @@ class DateTimeInput extends /* HTMLInputElement */ HTMLElement {
}
}
+ /**
+ Setting this to true disabled the time part of the input, and makes
+ any output only have date components (alternativly, the time component
+ set to zero).
+ */
get dateonly(): boolean {
return this.hasAttribute('dateonly');
}
@@ -74,6 +100,7 @@ class DateTimeInput extends /* HTMLInputElement */ HTMLElement {
this.dateonly = date.dateonly;
}
+ /** Returns current value as a Date object. */
get value(): Date {
let dt;
let date = this.date.value;
@@ -88,6 +115,7 @@ class DateTimeInput extends /* HTMLInputElement */ HTMLElement {
return dt;
}
+ /** Returns current value as an ISO-8601 formatted string. */
get stringValue(): string {
if (this.dateonly) {
return this.value.format("~Y-~m-~d")
diff --git a/static/ts/components/edit-rrule.ts b/static/ts/components/edit-rrule.ts
index a361bdee..b78171cc 100644
--- a/static/ts/components/edit-rrule.ts
+++ b/static/ts/components/edit-rrule.ts
@@ -1,3 +1,15 @@
+/**
+ * `<vevent-edit-rrule />`
+ *
+ * An edit form for a recurrence rule. Searches its template for elements
+ * with `[name="<<field name>>"]`, and binds to those.
+ *
+ * TODO rename this file
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { EditRRule }
import { ComponentVEvent } from './vevent'
diff --git a/static/ts/components/input-list.ts b/static/ts/components/input-list.ts
index 0afd4999..31dd5158 100644
--- a/static/ts/components/input-list.ts
+++ b/static/ts/components/input-list.ts
@@ -1,3 +1,13 @@
+/**
+ * `<input-list />`
+ *
+ * A list of identical input fields, which forms a group. For example
+ * useful to handle keywords.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { InputList }
/*
@@ -58,6 +68,10 @@ class InputList extends HTMLElement {
this.appendChild(new_el);
}
+ /**
+ * The value from each element, except the last which should always be empty.
+ * Has an unspecified type, since children:s value field might give non-strings.
+ */
get value(): any[] {
let value_list = []
for (let child of this.children) {
diff --git a/static/ts/components/popup-element.ts b/static/ts/components/popup-element.ts
index 458f543c..cc011ce3 100644
--- a/static/ts/components/popup-element.ts
+++ b/static/ts/components/popup-element.ts
@@ -1,3 +1,19 @@
+/**
+ * `<popup-element />`
+ *
+ * A (small) floating window containing information, which can be dragged
+ * arround. Consists of a navigation bar with a few buttons for
+ * controlling the window, which also works as a drag handle, along with
+ * an area for contents, which can be resized by the user.
+
+ * Currently tightly coupled to VEvent's, since their color
+ * profile is derived from their owning events calendar, and they have
+ * action buttons for the event in their navigation bar.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { PopupElement, setup_popup_element }
import { VEvent } from '../vevent'
@@ -7,12 +23,19 @@ import { ComponentVEvent } from './vevent'
import { remove_event } from '../server_connect'
-/* <popup-element /> */
+/**
+ ### Attributes
+ - visible
+ */
class PopupElement extends ComponentVEvent {
/* The popup which is the "selected" popup.
- /* Makes the popup last hovered over the selected popup, moving it to
+ * Makes the popup last hovered over the selected popup, moving it to
* the top, and allowing global keyboard bindings to affect it. */
+ /**
+ The popup which was most recently interacted with by the user. Used to
+ move it on top of all others, as well as sending relevant key events there.
+ */
static activePopup: PopupElement | null = null;
constructor(uid?: string) {
@@ -81,6 +104,12 @@ class PopupElement extends ComponentVEvent {
}
}
+ /**
+ If the popup is currently visible.
+
+ Adds the `visible` attribute to the component, which must then be handled
+ through CSS.
+ */
get visible(): boolean {
return this.hasAttribute('visible');
}
@@ -128,6 +157,10 @@ class PopupElement extends ComponentVEvent {
el.style.removeProperty('height');
}
+ /**
+ Resize the popup window to fill the current viewport (mostly). Is
+ probably bonud to the maximize button in the navigation bar.
+ */
maximize() {
/* TODO this assumes that popups are direct decendant of their parent,
which they really ought to be */
@@ -144,7 +177,8 @@ class PopupElement extends ComponentVEvent {
}
}
-/* Create a new popup element for the given VEvent, and ready it for editing the
+/**
+ Create a new popup element for the given VEvent, and ready it for editing the
event. Used when creating event (through the frontend).
The return value can safely be ignored.
*/
diff --git a/static/ts/components/tab-group-element.ts b/static/ts/components/tab-group-element.ts
index e90997e9..ce532cec 100644
--- a/static/ts/components/tab-group-element.ts
+++ b/static/ts/components/tab-group-element.ts
@@ -1,3 +1,40 @@
+/**
+ * `<tab-group />`
+
+A group of tabs, where only one can be visible at a time.
+
+@privateRemarks TODO which form does the HTML document have? For CSS purposes
+
+Each tab consists of two parts, a label which is used for selecting
+it, and a tab-element, which contains the actual content. These two
+should refer to each other as follows:
+
+@example
+```
++---------------+ +-----------------+
+| TabLabel | | Tab |
++---------------+ +-----------------+
+| id |<----| aria-labelledby |
+| aria-controls |---->| id |
++---------------+ +-----------------+
+```
+
+Further information about tabs in HTML can be found here:
+https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role
+
+#### CSS Variables
+
+##### tabcount
+Each tab element has the style property `--tabcount` set to how
+many tabs it has. This is mostly useful to make sure the tab context
+is large enough to fit all tab labels without overflowing.
+
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
+
import { ComponentVEvent } from './vevent'
import { makeElement, gensym } from '../lib'
import { EditRRule } from './edit-rrule'
@@ -6,7 +43,7 @@ import { vcal_objects } from '../globals'
export { TabGroupElement }
-/* Lacks a template, since it's trivial
+/** Lacks a template, since it's trivial
The initial children of this element all becomes tabs, each child may have
the datapropertys 'label' and 'title' set, where label is what is shown in
the tab bar, and title is the hower text.
@@ -81,6 +118,12 @@ class TabGroupElement extends ComponentVEvent {
} /* end connectedCallback */
+ /**
+ Adds a new tab to the group. The first parameter will make up the body
+ of the tab. The label is whath should be shown in the tab selector,
+ but defaults to the first letter of the text content of the body node.
+ Title is the hoover text of the label.
+ */
addTab(child: HTMLElement, label?: string, title?: string) {
/* First character of text is a good a guess as any for our label,
@@ -128,6 +171,10 @@ class TabGroupElement extends ComponentVEvent {
this.style.setProperty('--tabcount', '' + this.tabs.length);
}
+ /**
+ HTMLElement must be one of the tab bodies in this group. This method
+ removes it, along with its TabLabel.
+ */
removeTab(tab: HTMLElement) {
let id = tab.getAttribute('aria-labelledby')!
let label = document.getElementById(id)
diff --git a/static/ts/components/vevent-block.ts b/static/ts/components/vevent-block.ts
index 9bbb8e7e..374cf103 100644
--- a/static/ts/components/vevent-block.ts
+++ b/static/ts/components/vevent-block.ts
@@ -1,3 +1,14 @@
+/**
+ * `<vevent-block />`
+ *
+ * A block in our graphical view.
+ *
+ * Unique in that it works quite differently between the week and month view.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { ComponentBlock }
import { ComponentVEvent } from './vevent'
diff --git a/static/ts/components/vevent-description.ts b/static/ts/components/vevent-description.ts
index b44185e7..bf62c10d 100644
--- a/static/ts/components/vevent-description.ts
+++ b/static/ts/components/vevent-description.ts
@@ -1,3 +1,19 @@
+/**
+ * `<vevent-description />`
+
+A text representation of a VEvent. Used as the summary tab of our
+popup windows, and in the sidebar.
+
+When redrawn, it looks for an HTML-tag inside its template having the
+attribute `data-property` matching the properties name. If one is
+found, it looks in the `formatters` table
+({@link formatters}), for a field matching the property value, and
+defaults to the key `default`.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { ComponentDescription }
import { VEvent } from '../vevent'
diff --git a/static/ts/components/vevent-dl.ts b/static/ts/components/vevent-dl.ts
index a792c07f..a4b51dd9 100644
--- a/static/ts/components/vevent-dl.ts
+++ b/static/ts/components/vevent-dl.ts
@@ -1,3 +1,15 @@
+/**
+ * `<vevent-dl />`
+ *
+ * A description list of a vevent, used for debugging.
+ *
+ * No guarantees are given about the contents of the data fields, more
+ * than that they are related to the value in question.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
export { VEventDL }
import { ComponentVEvent } from './vevent'
diff --git a/static/ts/components/vevent-edit.ts b/static/ts/components/vevent-edit.ts
index e3b5d105..5dd39ee9 100644
--- a/static/ts/components/vevent-edit.ts
+++ b/static/ts/components/vevent-edit.ts
@@ -1,3 +1,14 @@
+/**
+ * `<vevent-edit />`
+ *
+ * Edit form for a vevent, designed for useful human interaction (and
+ * thereby not being all-encompassing).
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
+
export { ComponentEdit }
import { ComponentVEvent } from './vevent'
diff --git a/static/ts/components/vevent.ts b/static/ts/components/vevent.ts
index 7487cbb6..1d400e1e 100644
--- a/static/ts/components/vevent.ts
+++ b/static/ts/components/vevent.ts
@@ -1,18 +1,34 @@
+/**
+ * Root component for all events which content is closely linked to a `VEvent` object
+ *
+ * Lacks an accompaning tag, and shouldn't be directly instanciated.
+ *
+ * Note that many of these assume that their initial children are
+ * configured specifically, that is however not completely documented.
+ *
+ * @category Web Components
+ * @mergeTarget components
+ * @module
+ */
+
export { ComponentVEvent }
import { vcal_objects } from '../globals'
import { VEvent } from '../vevent'
-/* Root component for all events which content is closely linked to a
-@code{VEvent} object
-
-Lacks an accompaning tag, and shouldn't be directly instanciated.
-*/
abstract class ComponentVEvent extends HTMLElement {
template?: HTMLTemplateElement
uid: string
+ /**
+ * This registeres itself, but doesn't redraw
+ * We do however redraw in connectedCallback
+
+ * @privateRemarks
+ * TODO what is done in the default constructor,
+ * and the default connectedCallback
+ */
constructor(uid?: string) {
super();
this.template = document.getElementById(this.tagName.toLowerCase()) as HTMLTemplateElement | undefined
@@ -64,6 +80,7 @@ abstract class ComponentVEvent extends HTMLElement {
}
}
+ /** While abstract for this, @emph{must} be overridden for everyone else */
abstract redraw(data: VEvent): void
}
diff --git a/static/ts/formatters.ts b/static/ts/formatters.ts
index e0018278..05f84d31 100644
--- a/static/ts/formatters.ts
+++ b/static/ts/formatters.ts
@@ -1,3 +1,19 @@
+/**
+ * Formatting procedures used by some components.
+ *
+ * // TODO can we have a backref of every node containing {@link formatters-proc}?
+ *
+ * {@label formatters}
+ *
+ * Each procedure takes three arguments. The HTML-element which contents
+ * should be replaced, the VEvent containing all data, and the target
+ * value, as returned by {@link VEvent.getProperty}.
+ *
+ * Also bound to the window object.
+ *
+ * @module
+ */
+
export {
format
}
@@ -16,6 +32,10 @@ declare global {
let formatters: Map<string, formatter>;
formatters = window.formatters = new Map();
+/**
+ * Checks if a specific formatter exists for the given key, and executes it.
+ * Defaults to 'default', and also runs that if the regular formatter throws.
+ */
async function format(targetElement: HTMLElement, data: VEvent, key: string): Promise<void> {
let d = data.getProperty(key);
if (!d) return
diff --git a/static/ts/globals.ts b/static/ts/globals.ts
index 243e15e4..75fb1df9 100644
--- a/static/ts/globals.ts
+++ b/static/ts/globals.ts
@@ -1,3 +1,10 @@
+/**
+ * Different variables and values which for different reasons needs to be
+ * global. Window Value's are those that are bound to the `window`
+ * context in JavaScript, so is really always available, no opt out.
+ * @module
+ */
+
export {
find_block,
vcal_objects, event_calendar_mapping
@@ -10,14 +17,38 @@ import { ComponentBlock } from './components/vevent-block'
import { v4 as uuid } from 'uuid'
import { setup_popup_element } from './components/popup-element'
+/**
+ * All VEvent objects on current page, indexed by their unique identifiers.
+ *
+ * A global object store.
+ *
+ * Also bound to the window object for easy access.
+ */
const vcal_objects: Map<uid, VEvent> = new Map;
+
+/**
+ * Mapping from VEvent unique identifier, to name of its calendar. Should
+ * probably not be global, so refrain from using it.
+ */
const event_calendar_mapping: Map<uid, string> = new Map;
declare global {
interface Window {
vcal_objects: Map<uid, VEvent>;
+ /**
+ * How the calendar is currently formatted. Should be set by the backend
+ * through a simple `script`-tag.
+ */
VIEW: 'month' | 'week';
+ /**
+ * However editing of events is enabled or not.
+ * Should be set by the backend through a simple `script`-tag.
+ */
EDIT_MODE: boolean;
+ /**
+ * Name of the calendar to assume when creating new events.
+ * Should be set by the backend through a simple `script`-tag.
+ */
default_calendar: string;
addNewEvent(): void;
diff --git a/static/ts/jcal.ts b/static/ts/jcal.ts
index 41f33db4..6a491e04 100644
--- a/static/ts/jcal.ts
+++ b/static/ts/jcal.ts
@@ -3,6 +3,10 @@ export { jcal_to_xcal }
import { xcal, ical_type, JCalProperty, JCal } from './types'
import { asList } from './lib'
+/**
+ * A document with the xcal namespace, and @code{icalendar} as its root
+ * element. Each child is a valid xcal representation of our JCal object.
+ */
function jcal_type_to_xcal(doc: Document, type: ical_type, value: any): Element {
let el = doc.createElementNS(xcal, type);
switch (type) {
diff --git a/static/ts/lib.ts b/static/ts/lib.ts
index 2ef5b596..14cdd4f2 100644
--- a/static/ts/lib.ts
+++ b/static/ts/lib.ts
@@ -1,3 +1,86 @@
+/**
+ * General procedures which in theory could be used anywhere.
+ *
+ * Besides exporting the mentioned functions, this module also extends some base
+ * classes.
+ *
+ * ```tex
+@node Default prototype extensions
+@subsubsection Default prototype extensions
+
+
+
+@defmethod HTMLElement addEventListener name proc
+Replace the default @code{addEventListener} with a version that stores
+all listeners in the dictionary @var{listeners}.
+@end defmethod
+
+@defivar HTMLElement listeners
+Dictionary of all registered listeners to this element.
+Keys are taken from @code{addEventListener}.
+@end defivar
+
+@defmethod DOMTokenList find regexp
+Finds the first element of the DOMTokenList whichs value matches
+the supplied regexp. Returns a pair of the index and the value.
+@end defmethod
+
+@defmethod Object format args ...
+Returns a string representation of the given object.
+Allows extending for custom types,
+@ref{date-format}
+@end defmethod
+ * ```
+ *
+ * ---
+ *
+ * ```tex
+Some extensions to the builtin class ``Date'' is made.
+
+@defivar Date utc
+Boolean indicating if the given timestamp is in UTC or local time.
+true means UTC.
+@end defivar
+
+@defivar Date dateonly
+Boolean indicating if the time component of the Date object should be disregarded.
+@end defivar
+
+ * ```
+ * ```tex
+@defmethod Date format str args ...
+@anchor{date-format}
+Formats a Date object according to the format specification @var{str}.
+Keeping with Guile each format specifier starts with a ~.
+
+@table @samp
+@item ~~
+literal ~
+@c Almost all fields are left padded. How do I signify this
+@c with a single footnote?
+@item ~Y
+year, left-padding with zeroes.
+@item ~m
+month number, left padded with zeroes.
+@item ~d
+day of month.
+@item ~H
+hour
+@item ~M
+minute
+@item ~S
+second
+@item ~Z
+'Z' if Date is UTC, otherwise nothing
+@item ~L
+Converts the date to local time
+(@pxref{to_local}) (doesn't modify source object). Outputs nothing
+@end table
+@end defmethod
+```
+ *
+ * @module
+ */
export {
makeElement, date_to_percent,
parseDate, gensym, to_local, to_boolean,
@@ -5,10 +88,6 @@ export {
}
/*
- General procedures which in theory could be used anywhere.
- */
-
-/*
* https://www.typescriptlang.org/docs/handbook/declaration-merging.html
*/
declare global {
@@ -16,6 +95,7 @@ declare global {
format: (fmt: string) => string
}
+ /** HTMLElement extensions */
interface HTMLElement {
_addEventListener: (name: string, proc: (e: Event) => void) => void
listeners: Map<string, ((e: Event) => void)[]>
@@ -70,6 +150,13 @@ HTMLElement.prototype.getListeners = function() {
century, due to how javascript works (...).
*/
+/**
+ * Takes a string `str`, which should be in ISO-8601 date-format, and
+ * returns a javascript Date object.
+ * Handles date-times, with and without seconds, trailing `Z' for
+ * time-zones, and dates without times.
+ * If no time is given the `dateonly` attribute is set to yes.
+ */
function parseDate(str: string): Date {
let year: number;
let month: number;
@@ -112,6 +199,12 @@ function parseDate(str: string): Date {
return date;
}
+/* @anchor{to_local} */
+/**
+ * Returns a Date object (which may be new) which is guaranteed in local time.
+ * This means that the `utc` field is `false`, and that
+ * `to_local(current_time())` should show what your wall-clock shows.
+ */
function to_local(date: Date): Date {
if (!date.utc) return date;
@@ -120,6 +213,27 @@ function to_local(date: Date): Date {
/* -------------------------------------------------- */
+/**
+ * Creates a new DOM element of type `name`, with all keys in
+ * `attr` transfered to it. For example, the equivalent of
+
+ * ```html
+ * <input type='number'/>
+ * ```
+
+ * would be
+
+ * ```js
+ * values.push(makeElement('input', {
+ * type: 'number',
+ * }));
+ * ```
+ *
+ * @param name HTML tagname
+ * @param attr Attributes which will be set on the created element.
+ * @param actualAttr Attributes which will be set on the created element,
+ * but through `el.setAttribute` instead of `el[key] =`...
+ */
function makeElement(name: string, attr = {}, actualAttr = {}): HTMLElement {
let element: HTMLElement = document.createElement(name);
for (let [key, value] of Object.entries(attr)) {
@@ -131,6 +245,7 @@ function makeElement(name: string, attr = {}, actualAttr = {}): HTMLElement {
return element;
}
+/** TODO document me */
function round_time(time: number, fraction: number): number {
let scale = 1 / fraction;
return Math.round(time * scale) / scale;
@@ -142,14 +257,26 @@ function round_time(time: number, fraction: number): number {
Just doing (new Date()/(86400*1000)) would be nice, but there's no good
way to get the time in the current day.
*/
+/**
+ * Retuns how far along the date specified by `date` is, between 0
+ * and 100, where 00:00 maps to 0, and 23:59 to ~100.
+ */
function date_to_percent(date: Date): number /* in 0, 100 */ {
return (date.getHours() + (date.getMinutes() / 60)) * 100 / 24;
}
/* if only there was such a thing as a let to wrap around my lambda... */
/* js infix to not collide with stuff generated backend */
+/**
+ * Generates a new string which is (hopefully) globally unique.
+ * Compare with `gensym` from Lisp.
+ */
const gensym = (counter => (prefix = "gensym") => prefix + "js" + ++counter)(0)
+/**
+ * Ensures that `thing` is a list. Returning it outright if it
+ * already is one, otherwise wrapping it in a list.
+*/
function asList<T>(thing: Array<T> | T): Array<T> {
if (thing instanceof Array) {
return thing;
@@ -182,6 +309,7 @@ function datepad(thing: number | string, width = 2): string {
return (thing + "").padStart(width, "0");
}
+/** Equivalent to `date.format(str)` */
function format_date(date: Date, str: string): string {
let fmtmode = false;
let outstr = "";
diff --git a/static/ts/server_connect.ts b/static/ts/server_connect.ts
index 29f5bab2..ad4bc9eb 100644
--- a/static/ts/server_connect.ts
+++ b/static/ts/server_connect.ts
@@ -1,3 +1,9 @@
+/**
+ * Procedures for interfacing with the backend server.
+ *
+ * @module
+ */
+
export { create_event, remove_event }
import { jcal_to_xcal } from './jcal'
@@ -6,6 +12,15 @@ import { uid } from './types'
import { vcal_objects } from './globals'
import { PopupElement } from './components/popup-element'
+/**
+ * Requests that the server permanently remove the event with the given
+ * unique id from its persistant storage.
+ *
+ * If the server responds with a success also delete it from our local
+ * store (`vcal_objects`).
+ *
+ * // TODO link to our backend flow here
+*/
async function remove_event(uid: uid) {
let element = vcal_objects.get(uid);
if (!element) {
@@ -55,6 +70,13 @@ async function remove_event(uid: uid) {
// ];
// }
+/**
+ * Packs up the given event and sends it to the server to either be
+ * created, or simply be updated in the persistant database.
+
+ * Also does some minor updates registered components, to show that the
+ * event is actually created.
+*/
async function create_event(event: VEvent) {
// let xml = event.getElementsByTagName("icalendar")[0].outerHTML
diff --git a/static/ts/types.ts b/static/ts/types.ts
index 64e2c709..a0ab74a4 100644
--- a/static/ts/types.ts
+++ b/static/ts/types.ts
@@ -1,3 +1,8 @@
+/**
+ * Collection of type information for calendar data.
+ * @module
+ */
+
export {
ical_type,
valid_input_types,
@@ -6,6 +11,8 @@ export {
ChangeLogEntry
}
+
+/** Name of all valid icalendar types. */
let all_types = [
'text',
'uri',
@@ -23,6 +30,7 @@ let all_types = [
]
+/* The union of all elements in `all_types`. */
type ical_type
= 'text'
| 'uri'
@@ -39,6 +47,10 @@ type ical_type
| 'boolean'
| 'unknown'
+/**
+ * All known names properties (top level keys) can have.
+ * Such as "calscale", "dtstart", ...
+ */
let property_names = [
'calscale', 'method', 'prodid', 'version', 'attach', 'categories',
'class', 'comment', 'description', 'geo', 'location', 'percent-complete',
@@ -50,6 +62,15 @@ let property_names = [
];
+/**
+ * Which property fields each component can hold.
+ *
+ * ```json
+ * { 'VCALENDAR': ['PRODID', 'VERSION', 'CALSCALE', 'METHOD'],
+ * ...
+ * }
+ * ```
+ */
let valid_fields: Map<string, string[]> = new Map([
['VCALENDAR', ['PRODID', 'VERSION', 'CALSCALE', 'METHOD']],
['VEVENT', ['DTSTAMP', 'UID', 'DTSTART', 'CLASS', 'CREATED',
@@ -130,6 +151,18 @@ type known_ical_types
| 'URL'
| 'VERSION'
+/**
+ * Which types are valid to store under each property.
+ * If multiple values are an option for that property, then
+ * the list of possibilities will contain a sub-list (see example).
+ *
+ * ```json
+ * { 'DTSTART': ['date', 'date-time'],
+ * 'CATEGORIES': [['text']],
+ * ...
+ * }
+ * ```
+ */
let valid_input_types: Map<string, Array<ical_type | ical_type[]>> =
new Map([
['ACTION', ['text']], // AUDIO|DISPLAY|EMAIL|*other*
@@ -184,20 +217,35 @@ let valid_input_types: Map<string, Array<ical_type | ical_type[]>> =
// type JCalLine {
// }
+/** Alias of (`'vevent' | string`). */
type tagname = 'vevent' | string
+/** Alias of `string`. */
type uid = string
/* TODO is this type correct?
What really are valid values for any? Does that depend on ical_type? Why is the tail a list?
What really is the type for the parameter map?
*/
+/* TODO link to RFC 7265 (jCal) */
+/**
+ * Alias for a record consisting of
+ * - the name of the type, as a string
+ * - all parameters of the object, as a `Record<String, any>`
+ * - An `ical_type` value, noting the type of the final field(s)
+ * - and one or more values of the type specified by the third field.
+ */
type JCalProperty
= [string, Record<string, any>, ical_type, any]
| [string, Record<string, any>, ical_type, ...any[]]
+/**
+ * A record consisting of a `tagname`, a list of
+ * `JCalProperties`, and a list of other `JCal` objects.
+*/
type JCal = [tagname, JCalProperty[], JCal[]]
+/** The xml namespace name for xcalendar */
const xcal = "urn:ietf:params:xml:ns:icalendar-2.0";
interface ChangeLogEntry {
diff --git a/static/ts/vevent.ts b/static/ts/vevent.ts
index f3606f70..07f25d02 100644
--- a/static/ts/vevent.ts
+++ b/static/ts/vevent.ts
@@ -7,11 +7,12 @@ export {
isRedrawable,
}
-/* Something which can be redrawn */
+/** Something which can be redrawn */
interface Redrawable extends HTMLElement {
redraw(data: VEvent): void
}
+/** Checks if the given element is an instance of Redrawable. */
function isRedrawable(x: HTMLElement): x is Redrawable {
return 'redraw' in x
}
@@ -32,6 +33,10 @@ class VEventValue {
this.parameters = parameters;
}
+ /**
+ * The return value is *almost* a `JCalProperty`, just without
+ * the field name.
+ */
to_jcal(): [Record<string, any>, ical_type, any] {
let value;
let v = this.value;
@@ -88,6 +93,13 @@ type list_values
Abstract representation of a calendar event (or similar).
All "live" calendar data in the frontend should live in an object of this type.
*/
+/**
+ * Component for a single instance of a calendar event. Almost all data
+ * access should go through `getProperty` and `setProperty`,
+ * with the exception of the current calendar (which is accessed directly
+ * through `calendar`). Almost all changes through these interfaces
+ * are logged, and can be viewed through `changelog`.
+ */
class VEvent {
/* Calendar properties */
@@ -103,10 +115,16 @@ class VEvent {
#calendar: string | null = null;
+ /**
+ * Every write through getProperty gets logged here, and can be
+ * consumed. Hopefully this will one day turn into an undo system.
+ * TODO ref ChangeLogEntry.
+ */
#changelog: ChangeLogEntry[] = []
/* Iterator instead of direct return to ensure the receiver doesn't
modify the array */
+ /** Public (read only) interface to changelog. */
get changelog(): IterableIterator<[number, ChangeLogEntry]> {
return this.#changelog.entries();
}
@@ -156,6 +174,19 @@ class VEvent {
// getProperty(key: 'categories'): string[] | undefined
+ /**
+ * Returns the value of the given property if set, or undefined otherwise.
+ *
+ * For the keys
+ *
+ * - `'CATEGORIES'`,
+ * - `'RESOURCES'`,
+ * - `'FREEBUSY'`,
+ * - `'EXDATE'`, and
+ * - `'RDATE'`
+ *
+ * instead returns a list list of values.
+ */
getProperty(key: string): any | any[] | undefined {
key = key.toUpperCase()
let e = this.properties.get(key);
@@ -166,6 +197,7 @@ class VEvent {
return e.value;
}
+ /** Returns an iterator of all our properties. */
get boundProperties(): IterableIterator<string> {
return this.properties.keys()
}
@@ -228,6 +260,18 @@ class VEvent {
setProperty(key: list_values, value: any[], type?: ical_type): void;
setProperty(key: string, value: any, type?: ical_type): void;
+ /**
+ * Sets the given property to the given value. If type is given it's
+ * stored alongside the value, possibly updating what is already
+ * there. Do however note that no validation between the given type and
+ * the type of the value is done.
+ *
+ * `value` may also be a list, but should only be so for the keys
+ * mentioned in `getProperty`.
+ *
+ * After the value is set, `redraw` is called on all registered
+ * objects, notifying them of the change.
+ */
setProperty(key: string, value: any, type?: ical_type) {
this.setPropertyInternal(key, value, type);
@@ -236,6 +280,10 @@ class VEvent {
}
}
+ /**
+ * Equivalent to running `setProperty` for each element in the input
+ * list, but only calls `redraw` once at the end.
+ */
setProperties(pairs: [string, any, ical_type?][]) {
for (let pair of pairs) {
this.setPropertyInternal(...pair);
@@ -245,7 +293,7 @@ class VEvent {
}
}
-
+ /** The name of the calendar which this event belongs to. */
set calendar(calendar: string | null) {
this.addlog({
type: 'calendar',
@@ -263,14 +311,20 @@ class VEvent {
return this.#calendar;
}
+ /**
+ * Register something redrawable, which will be notified whenever this
+ * VEvents data is updated.
+ */
register(htmlNode: Redrawable) {
this.registered.push(htmlNode);
}
+ /** Stop recieving redraw events on the given component. */
unregister(htmlNode: Redrawable) {
this.registered = this.registered.filter(node => node !== htmlNode)
}
+ /** Converts the object to JCal data. */
to_jcal(): JCal {
let out_properties: JCalProperty[] = []
console.log(this.properties);
@@ -332,6 +386,7 @@ class RecurrenceRule {
bysetpos?: number[]
wkst?: weekday
+ /** Converts ourselves to JCal data. */
to_jcal(): Record<string, any> {
let obj: any = {}
if (this.freq) obj['freq'] = this.freq;
@@ -368,6 +423,7 @@ class RecurrenceRule {
}
}
+/** Parse a XCAL recurrence rule into a RecurrenceRule object. */
function xml_to_recurrence_rule(xml: Element): RecurrenceRule {
let rr = new RecurrenceRule;
@@ -507,6 +563,7 @@ function make_vevent_value_(value_tag: Element): string | boolean | Date | numbe
}
}
+/** Parse a complete XCAL object into a JS VEvent object. */
function xml_to_vcal(xml: Element): VEvent {
/* xml MUST have a VEVENT (or equivalent) as its root */
let properties = xml.getElementsByTagName('properties')[0];
diff --git a/static/tsconfig.json b/static/tsconfig.json
index 69d8fe06..c421a586 100644
--- a/static/tsconfig.json
+++ b/static/tsconfig.json
@@ -34,9 +34,13 @@
"include": ["**/*"],
"exclude": ["node_modules", "**/*.spec.ts"],
"typedocOptions": {
- "entryPointStrategy": "expand",
- "entryPoints": ["./ts"],
- "exclude": ["node_modules"],
- "out": "docs"
+ "entryPointStrategy": "expand",
+ "entryPoints": ["./ts"],
+ "exclude": ["node_modules"],
+ "plugin": [
+ "@mxssfd/typedoc-theme"
+ ],
+ "theme": "my-theme",
+ "out": "docs"
}
}