aboutsummaryrefslogtreecommitdiff
path: root/static
diff options
context:
space:
mode:
Diffstat (limited to 'static')
-rw-r--r--static/Makefile15
-rw-r--r--static/_global.scss1
-rw-r--r--static/components/date-time-input.ts2
-rw-r--r--static/components/vevent-description.ts26
-rw-r--r--static/directory-listing.scss5
-rw-r--r--static/formatters.ts35
-rw-r--r--static/globals.ts2
-rwxr-xr-xstatic/make-watch23
-rw-r--r--static/style.scss16
-rw-r--r--static/user/.gitignore2
-rw-r--r--static/user/user-additions.js62
-rw-r--r--static/vevent.ts5
12 files changed, 159 insertions, 35 deletions
diff --git a/static/Makefile b/static/Makefile
index b85422a3..1979575d 100644
--- a/static/Makefile
+++ b/static/Makefile
@@ -1,10 +1,11 @@
-.PHONY: all clean watch
+.PHONY: all install clean watch
-TARGETS := style.css smallcal.css script.out.js
+TARGETS := style.css smallcal.css script.out.js directory-listing.css
WATCH=
# script explicitly named, since that is our entry point
TS_FILES = script.ts $(shell find . -type f -name \*.ts -not -path */node_modules/*)
+JS_FILES = $(TS_FILES:%.ts=%.js)
export PATH := $(shell npm bin):$(PATH)
@@ -20,15 +21,11 @@ script.out.js: $(TS_FILES)
deps.svg: $(TS_FILES)
madge --image $@ $^
-# Note that 'tsc --watch' doesn't provide the files we are using. It's
-# just here for debug.
watch:
- tmux \
- new-session "scss --watch -I. style.scss:style.css" \; \
- split-window "tsc --watch" \; \
- rename-session "calp watch" \; \
- select-layout even-vertical
+ ./make-watch
+install: all
+ install -m644 -t $(DESTDIR)/usr/share/calp/www/ $(TARGETS)
clean:
rm $(TARGETS)
diff --git a/static/_global.scss b/static/_global.scss
index 41f426f9..58e05155 100644
--- a/static/_global.scss
+++ b/static/_global.scss
@@ -13,4 +13,5 @@ $popup-style: "left";
/* Each popup can have a different amoutn of tabs.
Override this as appropriate */
--tabcount: 4;
+ --background-color: white;
}
diff --git a/static/components/date-time-input.ts b/static/components/date-time-input.ts
index a6d5df18..005e4190 100644
--- a/static/components/date-time-input.ts
+++ b/static/components/date-time-input.ts
@@ -67,7 +67,7 @@ class DateTimeInput extends /* HTMLInputElement */ HTMLElement {
}
set value(date: Date) {
- let [d, t] = date.format("~L~Y-~m-~dT~H:~M:~S").split('T');
+ let [d, t] = date.format("~L~Y-~m-~dT~H:~M").split('T');
// console.log(d, t);
this.date.value = d;
this.time.value = t;
diff --git a/static/components/vevent-description.ts b/static/components/vevent-description.ts
index 4d81d6b3..f0d224be 100644
--- a/static/components/vevent-description.ts
+++ b/static/components/vevent-description.ts
@@ -2,7 +2,7 @@ export { ComponentDescription }
import { VEvent } from '../vevent'
import { ComponentVEvent } from './vevent'
-import { makeElement } from '../lib'
+import { formatters } from '../formatters'
/*
<vevent-description />
@@ -24,26 +24,12 @@ class ComponentDescription extends ComponentVEvent {
for (let el of body.querySelectorAll('[data-property]')) {
if (!(el instanceof HTMLElement)) continue;
let p = el.dataset.property!;
- let d, fmt;
+ let d;
if ((d = data.getProperty(p))) {
- switch (p.toLowerCase()) {
- case 'categories':
- for (let item of d) {
- let q = encodeURIComponent(
- `(member "${item}" (or (prop event (quote CATEGORIES)) (quote ())))`)
- el.appendChild(makeElement('a', {
- textContent: item,
- href: `/search/?q=${q}`,
- }))
- }
- break;
- default:
- if ((fmt = el.dataset.fmt)) {
- el.textContent = d.format(fmt);
- } else {
- el.textContent = d;
- }
- }
+ let key = p.toLowerCase();
+ let f = formatters.get(key);
+ if (f) f(el, d);
+ else window.formatters.get('default')!(el, d);
}
}
diff --git a/static/directory-listing.scss b/static/directory-listing.scss
new file mode 100644
index 00000000..745b5bc3
--- /dev/null
+++ b/static/directory-listing.scss
@@ -0,0 +1,5 @@
+@import 'global';
+
+.directory-table td:nth-child(3) {
+ text-align: end;
+}
diff --git a/static/formatters.ts b/static/formatters.ts
new file mode 100644
index 00000000..828a0e8b
--- /dev/null
+++ b/static/formatters.ts
@@ -0,0 +1,35 @@
+export {
+ formatters,
+}
+
+import { makeElement } from './lib'
+
+declare global {
+ interface Window {
+ formatters : Map<string, (e : HTMLElement, s : any) => void>;
+ }
+}
+
+let formatters : Map<string, (e : HTMLElement, s : any) => void>;
+formatters = window.formatters = new Map();
+
+
+formatters.set('categories', (el, d) => {
+ for (let item of d) {
+ let q = encodeURIComponent(
+ `(member "${item}" (or (prop event (quote CATEGORIES)) (quote ())))`)
+ el.appendChild(makeElement('a', {
+ textContent: item,
+ href: `/search/?q=${q}`,
+ }))
+ }
+})
+
+formatters.set('default', (el, d) => {
+ let fmt;
+ if ((fmt = el.dataset.fmt)) {
+ el.textContent = d.format(fmt);
+ } else {
+ el.textContent = d;
+ }
+})
diff --git a/static/globals.ts b/static/globals.ts
index eb7488c0..2fc12933 100644
--- a/static/globals.ts
+++ b/static/globals.ts
@@ -30,6 +30,8 @@ window.addNewEvent = () => {
let ev = new VEvent();
let uid = uuid()
let now = new Date()
+ /* Round seconds to 0, since time inputs wants exact seconds */
+ now.setUTCSeconds(0);
ev.setProperties([
['uid', uid],
['dtstart', now, 'date-time'],
diff --git a/static/make-watch b/static/make-watch
new file mode 100755
index 00000000..c985b37f
--- /dev/null
+++ b/static/make-watch
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+here=$(dirname "$(realpath "$0")")
+cd "$here" || {
+ echo "Failed to cd to location of script ($here)"
+ exit 1
+}
+
+export PATH="$here/node_modules/.bin:$PATH"
+
+# Note that 'tsc --watch' doesn't provide the files we are using. It's
+# just here for debug.
+if [ -n "$TMUX" ]; then
+ tmux new-window "scss --watch -I. style.scss:style.css"
+ tmux new-window "tsc --watch"
+else
+ tmux \
+ new-session "scss --watch -I. style.scss:style.css" \; \
+ split-window "tsc --watch" \; \
+ rename-session "calp watch" \; \
+ select-layout even-vertical
+
+ fi
diff --git a/static/style.scss b/static/style.scss
index efe8291d..c5705e24 100644
--- a/static/style.scss
+++ b/static/style.scss
@@ -11,6 +11,8 @@ html, body {
max-width: 100%;
height: 100%;
+ background-color: var(--background-color);
+
grid-template-columns: auto auto 20em;
grid-template-rows: auto;
@@ -227,10 +229,16 @@ Each event within the eventlist
padding-left: 2px;
margin-top: 1em;
- header h2 {
- width: 100%;
- text-align: center;
- font-size: 14pt;
+ header {
+ position: sticky;
+ top: 0;
+ background-color: var(--background-color);
+
+ h2 {
+ width: 100%;
+ text-align: center;
+ font-size: 14pt;
+ }
}
}
diff --git a/static/user/.gitignore b/static/user/.gitignore
new file mode 100644
index 00000000..6039f77d
--- /dev/null
+++ b/static/user/.gitignore
@@ -0,0 +1,2 @@
+!*.js
+salar.json
diff --git a/static/user/user-additions.js b/static/user/user-additions.js
new file mode 100644
index 00000000..c9ebe1a4
--- /dev/null
+++ b/static/user/user-additions.js
@@ -0,0 +1,62 @@
+window.formatters.set('description', (el, d) => {
+ if (/<br\/?>/.exec(d)) {
+ /* Assume that the text is HTML iff it contains a <br/> tag */
+ let parser = new DOMParser();
+ let doc = parser.parseFromString(d, 'text/html');
+ el.replaceChildren(doc.body);
+ } else {
+ /* Otherwise it should be plain(er) text, parse "all" links */
+ let rx = /https?:\/\/\S+/g
+ let idx = 0;
+ let children = []
+ for (let match of d.matchAll(rx)) {
+ let anch = document.createElement('a')
+ anch.href = match[0]
+ anch.textContent = match[0]
+
+ children.push(d.substring(idx, match.index))
+ children.push(anch)
+
+ idx = match.index + match[0].length
+ }
+ children.push(d.substring(idx))
+ el.replaceChildren(...children);
+ }
+})
+
+/* This location formatter is generally not for general use.
+ It holds a small lookup table of "all" locations at Linköping University,
+ and makes location names from their calendar system clickable.
+
+ To obtain salar.json, run scripts/fetch-liu-map-index.scm from calps source tree.
+*/
+
+window.salar = new Promise((resolve, reject) =>
+ fetch('/static/user/salar.json')
+ .then(d => d.json())
+ .then(d => resolve(d)))
+
+
+window.formatters.set('location', async function(el, d) {
+ let rx = /Lokal: (.*)/
+ let m = rx.exec(d)
+ if (! m) {
+ el.textContent = d;
+ return;
+ }
+
+ let salar = await window.salar;
+
+ let name = m[1]
+ let frag = salar[name];
+ if (frag) {
+ let anch = document.createElement('a');
+ anch.href = `https://old.liu.se/karta/${frag}`
+ anch.target = '_blank'
+ anch.textContent = name;
+ el.append('Lokal: ');
+ el.append(anch);
+ } else {
+ el.textContent = `Lokal: ${name}`
+ }
+})
diff --git a/static/vevent.ts b/static/vevent.ts
index cee26727..56c9019a 100644
--- a/static/vevent.ts
+++ b/static/vevent.ts
@@ -396,10 +396,13 @@ function xml_to_recurrence_rule(xml: Element): RecurrenceRule {
break;
case 'count':
- case 'interval':
rr.count = Number(t)
break;
+ case 'interval':
+ rr.interval = Number(t)
+ break;
+
case 'bysecond':
case 'byminute':
case 'byhour':