Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3758fc2116 | ||
|
|
15f9dce837 |
1509
lib/plankton/plankton.d.ts
vendored
1509
lib/plankton/plankton.d.ts
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,6 @@
|
|||
"path": ""
|
||||
},
|
||||
"misc": {
|
||||
"oidc_redirect_uri_template": "http://localhost:8888/?action=oidc_finish&session_key={{session_key}}",
|
||||
"use_central_europe_specific_datetime_inputs": true
|
||||
"oidc_redirect_uri_template": "http://localhost:8888/#oidc_finish,session_key={{session_key}}"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Beschreibung
|
||||
|
||||
- Web-Frontend für [zeitbild](/zeitbild/meta)
|
||||
- Web-Frontend für [`zeitbild`](https://forgejo.linke.sx/zeitbild/backend)
|
||||
|
||||
|
||||
## Erstellung
|
||||
|
|
|
|||
148
source/base.ts
148
source/base.ts
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
let _actions_login : Array<((name ?: (null | string)) => Promise<void>)> = [];
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _actions_logout : Array<(() => Promise<void>)> = [];
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _is_logged_in : boolean = false;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function listen_login(
|
||||
action : ((name ?: (null | string)) => Promise<void>)
|
||||
)
|
||||
: void
|
||||
{
|
||||
_actions_login.push(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function listen_logout(
|
||||
action : (() => Promise<void>)
|
||||
)
|
||||
: void
|
||||
{
|
||||
_actions_logout.push(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function notify_login(
|
||||
name : (null | string)
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
_is_logged_in = true;
|
||||
for (const action of _actions_login)
|
||||
{
|
||||
await action(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function notify_logout(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
_is_logged_in = false;
|
||||
for (const action of _actions_logout)
|
||||
{
|
||||
await action();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function is_logged_in(
|
||||
)
|
||||
: boolean
|
||||
{
|
||||
return _is_logged_in;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function oidc_finish(
|
||||
session_key : string
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
await _dali.backend.set_session_key(session_key);
|
||||
const status = await _dali.backend.status();
|
||||
if (! status.logged_in)
|
||||
{
|
||||
lib_plankton.log.error(
|
||||
"dali.oidc_login_failed"
|
||||
);
|
||||
await _dali.notify_logout();
|
||||
return Promise.reject<void>(new Error("oidc login failed"));
|
||||
}
|
||||
else
|
||||
{
|
||||
await _dali.notify_login(status.name);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function logout(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
try
|
||||
{
|
||||
await _dali.backend.session_end(
|
||||
);
|
||||
notify_logout();
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
lib_plankton.log.notice(
|
||||
"dali.logout_failed",
|
||||
{
|
||||
"reason": String(error),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,27 +14,10 @@
|
|||
"common.weekday.friday": "Fr",
|
||||
"common.weekday.saturday": "Sa",
|
||||
"common.weekday.sunday": "So",
|
||||
"common.monthname.january": "Jan",
|
||||
"common.monthname.february": "Feb",
|
||||
"common.monthname.march": "Mär",
|
||||
"common.monthname.april": "Apr",
|
||||
"common.monthname.may": "Mai",
|
||||
"common.monthname.june": "Jun",
|
||||
"common.monthname.july": "Jul",
|
||||
"common.monthname.august": "Aug",
|
||||
"common.monthname.september": "Sep",
|
||||
"common.monthname.october": "Okt",
|
||||
"common.monthname.november": "Nov",
|
||||
"common.monthname.december": "Dez",
|
||||
"common.open": "öffnen",
|
||||
"common.close": "schließen",
|
||||
"common.edit": "bearbeiten",
|
||||
"common.show": "zeigen",
|
||||
"common.hide": "ausblenden",
|
||||
"common.cancel": "abbrechen",
|
||||
"common.login": "anmelden",
|
||||
"common.logout": "abmelden",
|
||||
"common.confirm_deletion": "sicher?",
|
||||
"access_level.none": "nichts",
|
||||
"access_level.view": "nur lesen",
|
||||
"access_level.edit": "lesen und bearbeiten",
|
||||
|
|
@ -55,44 +38,46 @@
|
|||
"resource.kinds.caldav.read_only": "nur lesen",
|
||||
"calendar.calendar": "Kalender",
|
||||
"calendar.name": "Name",
|
||||
"calendar.hue": "Farbton",
|
||||
"calendar.resource": "Resource",
|
||||
"calendar.access.access": "Zugriff",
|
||||
"calendar.access.public": "öffentlich",
|
||||
"calendar.access.default_level": "Standard",
|
||||
"calendar.access.attributed_group": "Gruppen-Zuweisungen",
|
||||
"calendar.access.attributed_user": "Nutzer-Zuweisungen",
|
||||
"calendar.access.attributed": "Zuweisungen",
|
||||
"widget.listview.add": "Termin anlegen",
|
||||
"widget.weekview.controls.year": "Jahr",
|
||||
"widget.weekview.controls.week": "Woche",
|
||||
"widget.weekview.controls.count": "Anzahl",
|
||||
"widget.weekview.controls.vertical": "senkrecht",
|
||||
"widget.weekview.controls.apply": "Laden",
|
||||
"widget.calendar_edit.actions.add": "Kalender anlegen",
|
||||
"widget.calendar_edit.actions.change": "ändern",
|
||||
"widget.calendar_edit.actions.remove": "löschen",
|
||||
"widget.event_edit.actions.add": "anlegen",
|
||||
"widget.event_edit.actions.change": "ändern",
|
||||
"widget.event_edit.actions.remove": "löschen",
|
||||
"widget.sources.create": "Kalender anlegen",
|
||||
"widget.login.internal.name": "Name",
|
||||
"widget.login.internal.password": "Kennwort",
|
||||
"widget.login.internal.do": "Anmelden",
|
||||
"widget.login.oidc.via": "via {{title}}",
|
||||
"widget.caldav.title": "CalDAV",
|
||||
"widget.caldav.unavailable": "CalDAV nicht verfügbar",
|
||||
"widget.caldav.conf.title": "Zugangsdaten",
|
||||
"widget.caldav.conf.address": "Adresse (URL)",
|
||||
"widget.caldav.conf.username": "Nutzername",
|
||||
"widget.caldav.conf.password": "Kennwort",
|
||||
"widget.caldav.conf.setup_hints": "Einrichtungs-Hinweise",
|
||||
"widget.caldav.conf.token_unset": "es muss zunächst ein Token gesetzt werden",
|
||||
"widget.caldav.set_token.title": "Token setzen",
|
||||
"widget.caldav.set_token.action.set": "setzen",
|
||||
"widget.caldav.set_token.action.overwrite": "überschreiben",
|
||||
"widget.overview.title": "Übersicht",
|
||||
"widget.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen",
|
||||
"widget.overview.mode.week": "Wochen-Ansicht",
|
||||
"widget.overview.mode.list": "Listen-Ansicht"
|
||||
"page.login.title": "Anmelden",
|
||||
"page.login.internal.name": "Name",
|
||||
"page.login.internal.password": "Kennwort",
|
||||
"page.login.internal.do": "Anmelden",
|
||||
"page.login.oidc.via": "via {{title}}",
|
||||
"page.logout.title": "Abmelden",
|
||||
"page.caldav.title": "CalDAV",
|
||||
"page.caldav.unavailable": "CalDAV nicht verfügbar",
|
||||
"page.caldav.conf.title": "Zugangsdaten",
|
||||
"page.caldav.conf.address": "Adresse (URL)",
|
||||
"page.caldav.conf.username": "Nutzername",
|
||||
"page.caldav.conf.password": "Kennwort",
|
||||
"page.caldav.conf.setup_hints": "Einrichtungs-Hinweise",
|
||||
"page.caldav.conf.token_unset": "es muss zunächst ein Token gesetzt werden",
|
||||
"page.caldav.set_token.title": "Token setzen",
|
||||
"page.caldav.set_token.action.set": "setzen",
|
||||
"page.caldav.set_token.action.overwrite": "überschreiben",
|
||||
"page.calendar_add.title": "Kalendar anlegen",
|
||||
"page.calendar_add.actions.do": "anlegen",
|
||||
"page.calendar_edit.title.regular": "Kalendar bearbeiten",
|
||||
"page.calendar_edit.title.read_only": "Kalendar-Details",
|
||||
"page.calendar_edit.actions.change": "ändern",
|
||||
"page.calendar_edit.actions.remove": "löschen",
|
||||
"page.event_add.title": "Termin anlegen",
|
||||
"page.event_add.actions.do": "anlegen",
|
||||
"page.event_edit.title.regular": "Termin bearbeiten",
|
||||
"page.event_edit.title.read_only": "Termin-Details",
|
||||
"page.event_edit.actions.change": "ändern",
|
||||
"page.event_edit.actions.remove": "löschen",
|
||||
"page.overview.title": "Übersicht",
|
||||
"page.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,27 +14,10 @@
|
|||
"common.weekday.friday": "Fri",
|
||||
"common.weekday.saturday": "Sat",
|
||||
"common.weekday.sunday": "Sun",
|
||||
"common.monthname.january": "jan",
|
||||
"common.monthname.february": "feb",
|
||||
"common.monthname.march": "mar",
|
||||
"common.monthname.april": "apr",
|
||||
"common.monthname.may": "may",
|
||||
"common.monthname.june": "jun",
|
||||
"common.monthname.july": "jul",
|
||||
"common.monthname.august": "aug",
|
||||
"common.monthname.september": "sep",
|
||||
"common.monthname.october": "oct",
|
||||
"common.monthname.november": "nov",
|
||||
"common.monthname.december": "dec",
|
||||
"common.open": "open",
|
||||
"common.close": "close",
|
||||
"common.edit": "edit",
|
||||
"common.show": "show",
|
||||
"common.hide": "hide",
|
||||
"common.cancel": "cancel",
|
||||
"common.login": "login",
|
||||
"common.logout": "logout",
|
||||
"common.confirm_deletion": "sure?",
|
||||
"access_level.none": "none",
|
||||
"access_level.view": "read only",
|
||||
"access_level.edit": "read and write",
|
||||
|
|
@ -53,46 +36,48 @@
|
|||
"resource.kinds.caldav.title": "CalDAV",
|
||||
"resource.kinds.caldav.url": "URL",
|
||||
"resource.kinds.caldav.read_only": "read-only",
|
||||
"calendar.calendar": "calendar",
|
||||
"calendar.calendar": "Kalendar",
|
||||
"calendar.name": "name",
|
||||
"calendar.hue": "hue",
|
||||
"calendar.resource": "resource",
|
||||
"calendar.access.access": "access",
|
||||
"calendar.access.public": "public",
|
||||
"calendar.access.default_level": "default",
|
||||
"calendar.access.attributed_group": "group attributed",
|
||||
"calendar.access.attributed_user": "user attributed",
|
||||
"calendar.access.attributed": "attributed",
|
||||
"widget.listview.add": "add event",
|
||||
"widget.weekview.controls.year": "year",
|
||||
"widget.weekview.controls.week": "week",
|
||||
"widget.weekview.controls.count": "count",
|
||||
"widget.weekview.controls.vertical": "vertical",
|
||||
"widget.weekview.controls.year": "Year",
|
||||
"widget.weekview.controls.week": "Week",
|
||||
"widget.weekview.controls.count": "Count",
|
||||
"widget.weekview.controls.apply": "Load",
|
||||
"widget.calendar_edit.actions.add": "add calendar",
|
||||
"widget.calendar_edit.actions.change": "change",
|
||||
"widget.calendar_edit.actions.remove": "delete",
|
||||
"widget.event_edit.actions.add": "add",
|
||||
"widget.event_edit.actions.change": "change",
|
||||
"widget.event_edit.actions.remove": "delete",
|
||||
"widget.sources.create": "create calendar",
|
||||
"widget.login.internal.name": "name",
|
||||
"widget.login.internal.password": "password",
|
||||
"widget.login.internal.do": "login",
|
||||
"widget.login.oidc.via": "via {{title}}",
|
||||
"widget.caldav.title": "CalDAV",
|
||||
"widget.caldav.unavailable": "CalDAV not available",
|
||||
"widget.caldav.conf.title": "credentials",
|
||||
"widget.caldav.conf.address": "address (URL)",
|
||||
"widget.caldav.conf.username": "username",
|
||||
"widget.caldav.conf.password": "password",
|
||||
"widget.caldav.conf.setup_hints": "setup hints",
|
||||
"widget.caldav.conf.token_unset": "a token has to be set",
|
||||
"widget.caldav.set_token.title": "set token",
|
||||
"widget.caldav.set_token.action.set": "set",
|
||||
"widget.caldav.set_token.action.overwrite": "overwrite",
|
||||
"widget.overview.title": "Overview",
|
||||
"widget.overview.login_hint": "log in to view non-public events",
|
||||
"widget.overview.mode.week": "week view",
|
||||
"widget.overview.mode.list": "list view"
|
||||
"page.login.title": "Login",
|
||||
"page.login.internal.name": "name",
|
||||
"page.login.internal.password": "password",
|
||||
"page.login.internal.do": "login",
|
||||
"page.login.oidc.via": "via {{title}}",
|
||||
"page.logout.title": "Logout",
|
||||
"page.caldav.title": "CalDAV",
|
||||
"page.caldav.unavailable": "CalDAV not available",
|
||||
"page.caldav.conf.title": "credentials",
|
||||
"page.caldav.conf.address": "address (URL)",
|
||||
"page.caldav.conf.username": "username",
|
||||
"page.caldav.conf.password": "password",
|
||||
"page.caldav.conf.setup_hints": "setup hints",
|
||||
"page.caldav.conf.token_unset": "a token has to be set",
|
||||
"page.caldav.set_token.title": "set token",
|
||||
"page.caldav.set_token.action.set": "set",
|
||||
"page.caldav.set_token.action.overwrite": "overwrite",
|
||||
"page.calendar_add.title": "Add calendar",
|
||||
"page.calendar_add.actions.do": "anlegen",
|
||||
"page.event_add.title": "Add event",
|
||||
"page.event_add.actions.do": "add",
|
||||
"page.calendar_edit.title.regular": "Edit calendar",
|
||||
"page.calendar_edit.title.read_only": "Calendar details",
|
||||
"page.calendar_edit.actions.change": "change",
|
||||
"page.calendar_edit.actions.remove": "delete",
|
||||
"page.event_edit.title.regular": "Edit event",
|
||||
"page.event_edit.title.read_only": "Event details",
|
||||
"page.event_edit.actions.change": "change",
|
||||
"page.event_edit.actions.remove": "delete",
|
||||
"page.overview.title": "Overview",
|
||||
"page.overview.login_hint": "log in to view non-public events"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,394 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
namespace _dali.helpers
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo outsource
|
||||
*/
|
||||
function is_touch_device(
|
||||
)
|
||||
: boolean
|
||||
{
|
||||
return (
|
||||
("ontouchstart" in window)
|
||||
||
|
||||
(navigator.maxTouchPoints > 0)
|
||||
||
|
||||
(navigator["msMaxTouchPoints"] > 0)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _template_cache : Record<string, string> = {};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_mode_determine(
|
||||
mode_descriptor : string
|
||||
)
|
||||
: _dali.enum_view_mode
|
||||
{
|
||||
if (mode_descriptor === "auto")
|
||||
{
|
||||
return (
|
||||
(window.innerWidth >= 1000)
|
||||
?
|
||||
_dali.enum_view_mode.week
|
||||
:
|
||||
_dali.enum_view_mode.list
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return view_mode_decode(mode_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_kind_determine(
|
||||
mode_descriptor : string
|
||||
)
|
||||
: _dali.enum_view_kind
|
||||
{
|
||||
if (mode_descriptor === "auto")
|
||||
{
|
||||
return (
|
||||
is_touch_device()
|
||||
?
|
||||
_dali.enum_view_kind.touch
|
||||
:
|
||||
_dali.enum_view_kind.regular
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return view_kind_decode(mode_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function template_coin(
|
||||
group : string,
|
||||
name : string,
|
||||
data : Record<string, string>
|
||||
) : Promise<string>
|
||||
{
|
||||
let content : string;
|
||||
const key : string = lib_plankton.string.coin(
|
||||
"{{group}}/{{name}}",
|
||||
{
|
||||
"group": group,
|
||||
"name": name,
|
||||
}
|
||||
);
|
||||
if (! (key in _template_cache)) {
|
||||
content = (
|
||||
(
|
||||
await lib_plankton.file.read(
|
||||
lib_plankton.string.coin(
|
||||
"templates/{{group}}/{{name}}.html.tpl",
|
||||
{
|
||||
"group": group,
|
||||
"name": name,
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.toString()
|
||||
);
|
||||
_template_cache[key] = content;
|
||||
}
|
||||
else {
|
||||
content = _template_cache[key];
|
||||
}
|
||||
return Promise.resolve<string>(
|
||||
lib_plankton.string.coin(
|
||||
content,
|
||||
data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function element_from_template(
|
||||
group : string,
|
||||
name : string,
|
||||
data : Record<string, string>
|
||||
)
|
||||
: Promise<HTMLElement>
|
||||
{
|
||||
const dom_dummy = document.createElement("div");
|
||||
dom_dummy.innerHTML = await _dali.helpers.template_coin(
|
||||
group,
|
||||
name,
|
||||
data
|
||||
);
|
||||
return (dom_dummy.children[0] as HTMLElement);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo outsource
|
||||
*/
|
||||
export async function promise_row<type_result>(
|
||||
members : Array<
|
||||
() => Promise<type_result>
|
||||
>
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
type_result
|
||||
>
|
||||
>
|
||||
{
|
||||
let results : Array<type_result> = [];
|
||||
for await (const member of members) {
|
||||
results.push(await member());
|
||||
}
|
||||
return Promise.resolve<Array<type_result>>(results);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function input_access_level(
|
||||
)
|
||||
: lib_plankton.zoo_input.interface_input<_dali.enum_access_level>
|
||||
{
|
||||
return (
|
||||
new lib_plankton.zoo_input.class_input_wrapped<
|
||||
/*("none" | "view" | "edit" | "admin")*/string,
|
||||
_dali.enum_access_level
|
||||
>(
|
||||
new lib_plankton.zoo_input.class_input_selection(
|
||||
[
|
||||
{
|
||||
"value": "none",
|
||||
"label": lib_plankton.translate.get("access_level.none"),
|
||||
},
|
||||
{
|
||||
"value": "view",
|
||||
"label": lib_plankton.translate.get("access_level.view")
|
||||
},
|
||||
{
|
||||
"value": "edit",
|
||||
"label": lib_plankton.translate.get("access_level.edit")
|
||||
},
|
||||
{
|
||||
"value": "admin",
|
||||
"label": lib_plankton.translate.get("access_level.admin")
|
||||
},
|
||||
]
|
||||
),
|
||||
(raw) => {
|
||||
switch (raw) {
|
||||
case "none": return _dali.enum_access_level.none;
|
||||
case "view": return _dali.enum_access_level.view;
|
||||
case "edit": return _dali.enum_access_level.edit;
|
||||
case "admin": return _dali.enum_access_level.admin;
|
||||
}
|
||||
},
|
||||
(access_level) => {
|
||||
switch (access_level) {
|
||||
case _dali.enum_access_level.none: return "none";
|
||||
case _dali.enum_access_level.view: return "view";
|
||||
case _dali.enum_access_level.edit: return "edit";
|
||||
case _dali.enum_access_level.admin: return "admin";
|
||||
}
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function input_attributed_access_group(
|
||||
groups : Array<{id : _dali.type_group_id; object : _dali.type_group_object;}>
|
||||
)
|
||||
: lib_plankton.zoo_input.class_input_hashmap<
|
||||
_dali.type_group_id,
|
||||
_dali.enum_access_level
|
||||
>
|
||||
{
|
||||
return (
|
||||
new lib_plankton.zoo_input.class_input_hashmap<_dali.type_group_id, _dali.enum_access_level>(
|
||||
// hash_key
|
||||
(group_id) => group_id.toFixed(0),
|
||||
// key_input_factory
|
||||
() => new lib_plankton.zoo_input.class_input_wrapped<string, int>(
|
||||
new lib_plankton.zoo_input.class_input_selection(
|
||||
groups
|
||||
.map(
|
||||
(group) => ({
|
||||
"value": group.id.toFixed(0),
|
||||
"label": group.object.label,
|
||||
})
|
||||
)
|
||||
),
|
||||
x => parseInt(x),
|
||||
x => x.toFixed(0)
|
||||
),
|
||||
// value_input_factory
|
||||
() => input_access_level()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function input_attributed_access_user(
|
||||
users : Array<{id : _dali.type_user_id; name : string;}>
|
||||
)
|
||||
: lib_plankton.zoo_input.class_input_hashmap<
|
||||
_dali.type_user_id,
|
||||
_dali.enum_access_level
|
||||
>
|
||||
{
|
||||
return (
|
||||
new lib_plankton.zoo_input.class_input_hashmap<_dali.type_user_id, _dali.enum_access_level>(
|
||||
// hash_key
|
||||
(user_id) => user_id.toFixed(0),
|
||||
// key_input_factory
|
||||
() => new lib_plankton.zoo_input.class_input_wrapped<string, int>(
|
||||
new lib_plankton.zoo_input.class_input_selection(
|
||||
users
|
||||
.map(
|
||||
(user) => ({
|
||||
"value": user.id.toFixed(0),
|
||||
"label": user.name,
|
||||
})
|
||||
)
|
||||
),
|
||||
x => parseInt(x),
|
||||
x => x.toFixed(0)
|
||||
),
|
||||
// value_input_factory
|
||||
() => input_access_level()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function datetime_input(
|
||||
)
|
||||
: lib_plankton.zoo_input.interface_input<lib_plankton.pit.type_datetime>
|
||||
{
|
||||
return (
|
||||
_dali.conf.get().misc.use_central_europe_specific_datetime_inputs
|
||||
?
|
||||
new lib_plankton.zoo_input.class_input_datetime_central_europe(
|
||||
{
|
||||
"label_date": lib_plankton.translate.get("common.date"),
|
||||
"label_time": lib_plankton.translate.get("common.time"),
|
||||
}
|
||||
)
|
||||
:
|
||||
new lib_plankton.zoo_input.class_input_datetime(
|
||||
{
|
||||
"label_timezone_shift": lib_plankton.translate.get("common.timezone_shift"),
|
||||
"label_date": lib_plankton.translate.get("common.date"),
|
||||
"label_time": lib_plankton.translate.get("common.time"),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function event_color(
|
||||
hue : float
|
||||
)
|
||||
:
|
||||
string
|
||||
{
|
||||
return lib_plankton.color.output_hex(
|
||||
lib_plankton.color.make_hsv(
|
||||
{
|
||||
"hue": hue,
|
||||
"saturation": 0.375,
|
||||
"value": 0.375,
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function month_name(
|
||||
month : int
|
||||
)
|
||||
: string
|
||||
{
|
||||
const keys : Array<string> = [
|
||||
"common.monthname.january",
|
||||
"common.monthname.february",
|
||||
"common.monthname.march",
|
||||
"common.monthname.april",
|
||||
"common.monthname.may",
|
||||
"common.monthname.june",
|
||||
"common.monthname.july",
|
||||
"common.monthname.august",
|
||||
"common.monthname.september",
|
||||
"common.monthname.october",
|
||||
"common.monthname.november",
|
||||
"common.monthname.december",
|
||||
];
|
||||
return lib_plankton.translate.get(keys[month-1]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function loading(
|
||||
mode : boolean
|
||||
)
|
||||
: void
|
||||
{
|
||||
if (! mode)
|
||||
{
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
else
|
||||
{
|
||||
_dali.overlay.get_content_element().innerHTML = ". . .";
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => {
|
||||
_dali.main()
|
||||
_zeitbild.frontend_web.main()
|
||||
.then(
|
||||
() => {}
|
||||
)
|
||||
|
|
@ -20,14 +20,16 @@ document.addEventListener(
|
|||
)
|
||||
}
|
||||
);
|
||||
|
||||
</script>
|
||||
{{templates}}
|
||||
</head>
|
||||
<body>
|
||||
<div id="overlay">
|
||||
<div id="overlay_content">
|
||||
</div>
|
||||
</div>
|
||||
<header>
|
||||
<nav>
|
||||
<ul>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
</main>
|
||||
|
|
|
|||
630
source/logic/backend.ts
Normal file
630
source/logic/backend.ts
Normal file
|
|
@ -0,0 +1,630 @@
|
|||
/**
|
||||
*/
|
||||
namespace _zeitbild.frontend_web.backend
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
var _data_chest : (
|
||||
null
|
||||
|
|
||||
lib_plankton.storage.type_chest<string, string, void, string, string>
|
||||
) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function access_level_encode(
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level
|
||||
) : ("none" | "view" | "edit" | "admin")
|
||||
{
|
||||
switch (access_level) {
|
||||
case _zeitbild.frontend_web.type.enum_access_level.none: return "none";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.view: return "view";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function access_level_decode(
|
||||
access_level_encoded : ("none" | "view" | "edit" | "admin")
|
||||
) : _zeitbild.frontend_web.type.enum_access_level
|
||||
{
|
||||
switch (access_level_encoded) {
|
||||
case "none": return _zeitbild.frontend_web.type.enum_access_level.none;
|
||||
case "view": return _zeitbild.frontend_web.type.enum_access_level.view;
|
||||
case "edit": return _zeitbild.frontend_web.type.enum_access_level.edit;
|
||||
case "admin": return _zeitbild.frontend_web.type.enum_access_level.admin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function init(
|
||||
) : Promise<void>
|
||||
{
|
||||
_data_chest = lib_plankton.storage.localstorage.implementation_chest(
|
||||
{
|
||||
"corner": "zeitbild",
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function get_session_key(
|
||||
) : Promise<(null | string)>
|
||||
{
|
||||
try {
|
||||
return (await _data_chest.read("session_key"));
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function is_logged_in(
|
||||
) : Promise<boolean>
|
||||
{
|
||||
return ((await get_session_key()) !== null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function call(
|
||||
method : lib_plankton.http.enum_method,
|
||||
action : string,
|
||||
input : (null | any)
|
||||
) : Promise<any>
|
||||
{
|
||||
const with_body : boolean = (
|
||||
[
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.http.enum_method.patch,
|
||||
].includes(method)
|
||||
);
|
||||
const session_key : (null | string) = await get_session_key();
|
||||
const http_request : lib_plankton.http.type_request = {
|
||||
"version": "HTTP/2",
|
||||
"scheme": (
|
||||
(_zeitbild.frontend_web.conf.get()["backend"]["scheme"] === "http")
|
||||
?
|
||||
"http"
|
||||
:
|
||||
"https"
|
||||
),
|
||||
"host": lib_plankton.string.coin(
|
||||
"{{host}}:{{port}}",
|
||||
{
|
||||
"host": _zeitbild.frontend_web.conf.get()["backend"]["host"],
|
||||
"port": _zeitbild.frontend_web.conf.get()["backend"]["port"].toFixed(0),
|
||||
}
|
||||
),
|
||||
"path": lib_plankton.string.coin(
|
||||
"{{base}}{{action}}",
|
||||
{
|
||||
"base": _zeitbild.frontend_web.conf.get()["backend"]["path"],
|
||||
"action": action,
|
||||
}
|
||||
),
|
||||
"method": method,
|
||||
"query": (
|
||||
(with_body || (input === null))
|
||||
?
|
||||
null
|
||||
:
|
||||
("?" + lib_plankton.www_form.encode(input))
|
||||
),
|
||||
"headers": Object.assign(
|
||||
{},
|
||||
(
|
||||
(! with_body)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"Content-Type": "application/json"}
|
||||
),
|
||||
(
|
||||
(session_key === null)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"X-Session-Key": session_key}
|
||||
)
|
||||
),
|
||||
"body": (
|
||||
((! with_body) || (input === null))
|
||||
?
|
||||
null
|
||||
:
|
||||
/*Buffer.from*/(lib_plankton.json.encode(input))
|
||||
),
|
||||
};
|
||||
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(http_request);
|
||||
if (
|
||||
! (
|
||||
(http_response.status_code >= 200)
|
||||
&&
|
||||
(http_response.status_code < 300)
|
||||
)
|
||||
) {
|
||||
return Promise.reject<any>(http_response.body.toString());
|
||||
}
|
||||
else {
|
||||
const output : any = lib_plankton.json.decode(http_response.body.toString());
|
||||
return Promise.resolve<any>(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_prepare(
|
||||
input : any
|
||||
) : Promise<{kind : string; data : any;}>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
"/session/prepare",
|
||||
input
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function set_session_key(
|
||||
session_key : string
|
||||
) : Promise<void>
|
||||
{
|
||||
return (
|
||||
_data_chest.write("session_key", session_key)
|
||||
.then<void>(() => Promise.resolve<void>(undefined))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_begin(
|
||||
name : string,
|
||||
password : string
|
||||
) : Promise<void>
|
||||
{
|
||||
const session_key : string = await call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
"/session/begin",
|
||||
{
|
||||
"name": name,
|
||||
"password": password,
|
||||
}
|
||||
);
|
||||
await _data_chest.write("session_key", session_key);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_end(
|
||||
) : Promise<void>
|
||||
{
|
||||
await call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
"/session/end",
|
||||
null
|
||||
);
|
||||
await _data_chest.delete("session_key");
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_list(
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/users",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_dav_conf(
|
||||
) : Promise<
|
||||
(
|
||||
null
|
||||
|
|
||||
{
|
||||
address : string;
|
||||
username : string;
|
||||
password : string;
|
||||
setup_hints : Array<
|
||||
{
|
||||
label : string;
|
||||
link : string;
|
||||
remark : (null | string);
|
||||
}
|
||||
>;
|
||||
}
|
||||
)
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/user_dav_conf",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_dav_token(
|
||||
) : Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.patch,
|
||||
"/user_dav_token",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_list(
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return (
|
||||
call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/calendar",
|
||||
null
|
||||
)
|
||||
.then(
|
||||
(entries) => Promise.resolve(
|
||||
entries
|
||||
.map(
|
||||
(entry) => ({
|
||||
"id": entry.id,
|
||||
"name": entry.name,
|
||||
"access_level": access_level_decode(entry.access_level),
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_get(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id
|
||||
) : Promise<
|
||||
_zeitbild.frontend_web.type.calendar_object
|
||||
>
|
||||
{
|
||||
return (
|
||||
call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
)
|
||||
.then(
|
||||
(raw) => Promise.resolve(
|
||||
{
|
||||
"name": raw.name,
|
||||
"access": {
|
||||
"public": raw.access.public,
|
||||
"default_level": access_level_decode(raw.access.default_level),
|
||||
"attributed": lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
x => x.toFixed(0),
|
||||
{
|
||||
"pairs": (
|
||||
raw.access.attributed
|
||||
.map(
|
||||
(entry) => ({
|
||||
"key": entry.user_id,
|
||||
"value": access_level_decode(entry.level),
|
||||
})
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
),
|
||||
},
|
||||
// "resource_id": raw.resource_id
|
||||
// TODO
|
||||
"resource": {
|
||||
"kind": "local",
|
||||
"data": {
|
||||
"events": []
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_add(
|
||||
calendar_object : _zeitbild.frontend_web.type.calendar_object
|
||||
) : Promise<
|
||||
_zeitbild.frontend_web.type.calendar_id
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar",
|
||||
{
|
||||
}
|
||||
),
|
||||
{
|
||||
"name": calendar_object.name,
|
||||
"access": {
|
||||
"public": calendar_object.access.public,
|
||||
"default_level": access_level_encode(calendar_object.access.default_level),
|
||||
"attributed": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed)
|
||||
.map(
|
||||
(pair) => ({
|
||||
"user_id": pair.key,
|
||||
"level": access_level_encode(pair.value),
|
||||
})
|
||||
)
|
||||
)
|
||||
},
|
||||
"resource": calendar_object.resource,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_change(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
calendar_object : _zeitbild.frontend_web.type.calendar_object
|
||||
) : Promise<
|
||||
void
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
{
|
||||
"name": calendar_object.name,
|
||||
"access": {
|
||||
"public": calendar_object.access.public,
|
||||
"default_level": access_level_encode(calendar_object.access.default_level),
|
||||
"attributed": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed)
|
||||
.map(
|
||||
(pair) => ({
|
||||
"user_id": pair.key,
|
||||
"level": access_level_encode(pair.value),
|
||||
})
|
||||
)
|
||||
)
|
||||
},
|
||||
"resource": calendar_object.resource,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_remove(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id
|
||||
) : Promise<
|
||||
void
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_get(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
event_id : _zeitbild.frontend_web.type.local_resource_event_id
|
||||
) : Promise<_zeitbild.frontend_web.type.event_object>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_add(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
event_object : _zeitbild.frontend_web.type.event_object
|
||||
) : Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
event_object
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_change(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
event_id : _zeitbild.frontend_web.type.local_resource_event_id,
|
||||
event_object : _zeitbild.frontend_web.type.event_object
|
||||
) : Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
event_object
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_remove(
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
event_id : _zeitbild.frontend_web.type.local_resource_event_id
|
||||
) : Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo prevent loops
|
||||
*/
|
||||
export async function events(
|
||||
from_pit : lib_plankton.pit.type_pit,
|
||||
to_pit : lib_plankton.pit.type_pit,
|
||||
options : {
|
||||
calendar_ids ?: (null | Array<_zeitbild.frontend_web.type.calendar_id>);
|
||||
} = {}
|
||||
) : Promise<
|
||||
Array<
|
||||
{
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id;
|
||||
calendar_name : string;
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id);
|
||||
event_object : _zeitbild.frontend_web.type.event_object;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
options = Object.assign(
|
||||
{
|
||||
"calendar_ids": null,
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
return (
|
||||
call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/events",
|
||||
Object.assign(
|
||||
{
|
||||
"from": from_pit,
|
||||
"to": to_pit,
|
||||
},
|
||||
(
|
||||
(options.calendar_ids === null)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"calendar_ids": options.calendar_ids.join(",")}
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(
|
||||
(data) => Promise.resolve(
|
||||
data
|
||||
.map(
|
||||
(entry) => ({
|
||||
"calendar_id": entry.calendar_id,
|
||||
"calendar_name": entry.calendar_name,
|
||||
"access_level": access_level_decode(entry.access_level),
|
||||
"event_id": entry.event_id,
|
||||
"event_object": entry.event_object,
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,25 +1,5 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
namespace _dali.conf
|
||||
namespace _zeitbild.frontend_web.conf
|
||||
{
|
||||
|
||||
/**
|
||||
|
|
@ -73,16 +53,10 @@ namespace _dali.conf
|
|||
"default": "http://localhost:8888/#oidc_finish,session_key={{session_key}}"
|
||||
},
|
||||
"use_central_europe_specific_datetime_inputs": {
|
||||
"nullable": false,
|
||||
"nullable": true,
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"weekview_cell_day_format": {
|
||||
"nullable": false,
|
||||
"type": "string",
|
||||
"default": "d.b",
|
||||
"description": "available placeholders: Y,m,b,d,W,w (as in UNIX command 'date')"
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
],
|
||||
|
|
@ -99,25 +73,7 @@ namespace _dali.conf
|
|||
|
||||
/**
|
||||
*/
|
||||
type type_data = {
|
||||
version : string;
|
||||
backend : {
|
||||
scheme : string;
|
||||
host : string;
|
||||
port : int;
|
||||
path : string;
|
||||
};
|
||||
misc : {
|
||||
oidc_redirect_uri_template : string;
|
||||
use_central_europe_specific_datetime_inputs : string;
|
||||
weekview_cell_day_format : string;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _data : (null | type_data) = null;
|
||||
var _data : (null | any) = null;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -132,10 +88,9 @@ namespace _dali.conf
|
|||
/**
|
||||
*/
|
||||
export function get(
|
||||
) : type_data
|
||||
{
|
||||
if (_data === null)
|
||||
) : any
|
||||
{
|
||||
if (_data === null) {
|
||||
throw (new Error("conf not loaded yet"));
|
||||
}
|
||||
else {
|
||||
|
|
@ -150,7 +105,10 @@ namespace _dali.conf
|
|||
path : string
|
||||
) : Promise<void>
|
||||
{
|
||||
_data = ((await lib_plankton.conf.load(_schema, path)) as type_data);
|
||||
_data = await lib_plankton.conf.load(
|
||||
_schema,
|
||||
path
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
186
source/logic/helpers.ts
Normal file
186
source/logic/helpers.ts
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
|
||||
/**
|
||||
*/
|
||||
namespace _zeitbild.frontend_web.helpers
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
var _template_cache : Record<string, string> = {};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function template_coin(
|
||||
group : string,
|
||||
name : string,
|
||||
data : Record<string, string>
|
||||
) : Promise<string>
|
||||
{
|
||||
let content : string;
|
||||
const key : string = lib_plankton.string.coin(
|
||||
"{{group}}/{{name}}",
|
||||
{
|
||||
"group": group,
|
||||
"name": name,
|
||||
}
|
||||
);
|
||||
if (! (key in _template_cache)) {
|
||||
content = (
|
||||
(
|
||||
await lib_plankton.file.read(
|
||||
lib_plankton.string.coin(
|
||||
"templates/{{group}}/{{name}}.html.tpl",
|
||||
{
|
||||
"group": group,
|
||||
"name": name,
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
.toString()
|
||||
);
|
||||
_template_cache[key] = content;
|
||||
}
|
||||
else {
|
||||
content = _template_cache[key];
|
||||
}
|
||||
return Promise.resolve<string>(
|
||||
lib_plankton.string.coin(
|
||||
content,
|
||||
data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo outsource
|
||||
*/
|
||||
export async function promise_row<type_result>(
|
||||
members : Array<
|
||||
() => Promise<type_result>
|
||||
>
|
||||
) : Promise<
|
||||
Array<
|
||||
type_result
|
||||
>
|
||||
>
|
||||
{
|
||||
let results : Array<type_result> = [];
|
||||
for await (const member of members) {
|
||||
results.push(await member());
|
||||
}
|
||||
return Promise.resolve<Array<type_result>>(results);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function input_access_level(
|
||||
) : lib_plankton.zoo_input.interface_input<_zeitbild.frontend_web.type.enum_access_level>
|
||||
{
|
||||
return (
|
||||
new lib_plankton.zoo_input.class_input_wrapped<
|
||||
/*("none" | "view" | "edit" | "admin")*/string,
|
||||
_zeitbild.frontend_web.type.enum_access_level
|
||||
>(
|
||||
new lib_plankton.zoo_input.class_input_selection(
|
||||
[
|
||||
{
|
||||
"value": "none",
|
||||
"label": lib_plankton.translate.get("access_level.none"),
|
||||
},
|
||||
{
|
||||
"value": "view",
|
||||
"label": lib_plankton.translate.get("access_level.view")
|
||||
},
|
||||
{
|
||||
"value": "edit",
|
||||
"label": lib_plankton.translate.get("access_level.edit")
|
||||
},
|
||||
{
|
||||
"value": "admin",
|
||||
"label": lib_plankton.translate.get("access_level.admin")
|
||||
},
|
||||
]
|
||||
),
|
||||
(raw) => {
|
||||
switch (raw) {
|
||||
case "none": return _zeitbild.frontend_web.type.enum_access_level.none;
|
||||
case "view": return _zeitbild.frontend_web.type.enum_access_level.view;
|
||||
case "edit": return _zeitbild.frontend_web.type.enum_access_level.edit;
|
||||
case "admin": return _zeitbild.frontend_web.type.enum_access_level.admin;
|
||||
}
|
||||
},
|
||||
(access_level) => {
|
||||
switch (access_level) {
|
||||
case _zeitbild.frontend_web.type.enum_access_level.none: return "none";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.view: return "view";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin";
|
||||
}
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function input_attributed_access(
|
||||
) : Promise<lib_plankton.zoo_input.class_input_hashmap<_zeitbild.frontend_web.type.user_id, _zeitbild.frontend_web.type.enum_access_level>>
|
||||
{
|
||||
const users : Array<{id : _zeitbild.frontend_web.type.user_id; name : string;}> = await _zeitbild.frontend_web.backend.user_list(
|
||||
);
|
||||
return Promise.resolve(
|
||||
new lib_plankton.zoo_input.class_input_hashmap<_zeitbild.frontend_web.type.user_id, _zeitbild.frontend_web.type.enum_access_level>(
|
||||
// hash_key
|
||||
(user_id) => user_id.toFixed(0),
|
||||
// key_input_factory
|
||||
() => new lib_plankton.zoo_input.class_input_wrapped<string, int>(
|
||||
new lib_plankton.zoo_input.class_input_selection(
|
||||
users
|
||||
.map(
|
||||
(user) => ({
|
||||
"value": user.id.toFixed(0),
|
||||
"label": user.name,
|
||||
})
|
||||
)
|
||||
),
|
||||
x => parseInt(x),
|
||||
x => x.toFixed(0)
|
||||
),
|
||||
// value_input_factory
|
||||
() => input_access_level()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function datetime_input(
|
||||
) : lib_plankton.zoo_input.interface_input<lib_plankton.pit.type_datetime>
|
||||
{
|
||||
return (
|
||||
_zeitbild.frontend_web.conf.get().misc.use_central_europe_specific_datetime_inputs
|
||||
?
|
||||
new lib_plankton.zoo_input.class_input_datetime_central_europe(
|
||||
{
|
||||
"label_date": lib_plankton.translate.get("common.date"),
|
||||
"label_time": lib_plankton.translate.get("common.time"),
|
||||
}
|
||||
)
|
||||
:
|
||||
new lib_plankton.zoo_input.class_input_datetime(
|
||||
{
|
||||
"label_timezone_shift": lib_plankton.translate.get("common.timezone_shift"),
|
||||
"label_date": lib_plankton.translate.get("common.date"),
|
||||
"label_time": lib_plankton.translate.get("common.time"),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
79
source/logic/main.ts
Normal file
79
source/logic/main.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
/**
|
||||
*/
|
||||
namespace _zeitbild.frontend_web
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function main(
|
||||
) : Promise<void>
|
||||
{
|
||||
// conf
|
||||
await _zeitbild.frontend_web.conf.init(
|
||||
"conf.json"
|
||||
);
|
||||
|
||||
// init
|
||||
lib_plankton.log.set_main_logger(
|
||||
[
|
||||
{"kind": "console", "data": {"threshold": "info"}},
|
||||
]
|
||||
);
|
||||
await _zeitbild.frontend_web.backend.init(
|
||||
);
|
||||
await lib_plankton.translate.initialize(
|
||||
{
|
||||
"verbosity": 1,
|
||||
"packages": [
|
||||
JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")),
|
||||
JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")),
|
||||
],
|
||||
"order": ["deu", "eng"],
|
||||
"autopromote": false,
|
||||
}
|
||||
);
|
||||
lib_plankton.zoo_page.init(
|
||||
document.querySelector("main"),
|
||||
{
|
||||
"fallback": {
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
}
|
||||
);
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "login", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.login.title")}
|
||||
);
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "overview", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.overview.title")}
|
||||
);
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "calendar_add", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.calendar_add.title")}
|
||||
);
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "caldav", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.caldav.title")}
|
||||
);
|
||||
/*
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "event_add", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.event_add.title")}
|
||||
);
|
||||
*/
|
||||
lib_plankton.zoo_page.add_nav_entry(
|
||||
{"name": "logout", "parameters": {}},
|
||||
{"label": lib_plankton.translate.get("page.logout.title")}
|
||||
);
|
||||
|
||||
// exec
|
||||
lib_plankton.zoo_page.start();
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
114
source/logic/types.ts
Normal file
114
source/logic/types.ts
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
/**
|
||||
*/
|
||||
namespace _zeitbild.frontend_web.type
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_access_level {
|
||||
none,
|
||||
view,
|
||||
edit,
|
||||
admin
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type user_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type user_object = {
|
||||
name : string;
|
||||
email_address : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type event_object = {
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (
|
||||
null
|
||||
|
|
||||
lib_plankton.pit.type_datetime
|
||||
);
|
||||
location : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
link : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
description : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type local_resource_event_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type resource_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type resource_object = (
|
||||
{
|
||||
kind : "local";
|
||||
data : {
|
||||
events : Array<
|
||||
event_object
|
||||
>;
|
||||
};
|
||||
}
|
||||
|
|
||||
{
|
||||
kind : "caldav";
|
||||
data : {
|
||||
read_only : boolean;
|
||||
url : string;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type calendar_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type calendar_object = {
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : enum_access_level;
|
||||
attributed : lib_plankton.map.type_map<
|
||||
user_id,
|
||||
enum_access_level
|
||||
>;
|
||||
};
|
||||
resource : resource_object;
|
||||
};
|
||||
|
||||
}
|
||||
18
source/logic/widget.ts
Normal file
18
source/logic/widget.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
namespace _zeitbild
|
||||
{
|
||||
|
||||
/**
|
||||
* @todo outsource
|
||||
*/
|
||||
export abstract class class_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public abstract load(
|
||||
target_element : Element
|
||||
) : Promise<void>;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
221
source/main.ts
221
source/main.ts
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
namespace _dali
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function main(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
// conf
|
||||
await _dali.conf.init(
|
||||
"conf.json"
|
||||
);
|
||||
|
||||
// init:logger
|
||||
lib_plankton.log.set_main_logger(
|
||||
[
|
||||
{
|
||||
"kind": "minlevel",
|
||||
"data": {
|
||||
"core": {
|
||||
"kind": "console",
|
||||
"data": {
|
||||
}
|
||||
},
|
||||
"threshold": "info"
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
// init:overlay
|
||||
{
|
||||
await _dali.overlay.initialize();
|
||||
_dali.helpers.loading(true);
|
||||
}
|
||||
// init:localization
|
||||
{
|
||||
const order : Array<string> = ["deu", "eng"];
|
||||
await lib_plankton.translate.initialize(
|
||||
{
|
||||
"verbosity": 1,
|
||||
"packages": await Promise.all(
|
||||
order.map(
|
||||
code => (
|
||||
Promise.resolve(code)
|
||||
.then<string>(code => Promise.resolve(lib_plankton.string.coin("data/localization/{{code}}.loc.json", {"code": code})))
|
||||
.then<string>(lib_plankton.file.read)
|
||||
.then<any>(content => Promise.resolve(JSON.parse(content)))
|
||||
)
|
||||
)
|
||||
),
|
||||
"order": order,
|
||||
"autopromote": false,
|
||||
}
|
||||
);
|
||||
}
|
||||
// init:backend
|
||||
await _dali.backend.initialize(
|
||||
_dali.conf.get()["backend"]
|
||||
);
|
||||
// init:model
|
||||
await _dali.model.initialize(
|
||||
);
|
||||
// init:page
|
||||
lib_plankton.zoo_page.init(
|
||||
document.querySelector("main"),
|
||||
{
|
||||
"fallback": {
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
},
|
||||
}
|
||||
);
|
||||
// init:menu
|
||||
{
|
||||
const widget_menu : _dali.widgets.class_widget_menu = new _dali.widgets.class_widget_menu(
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("common.login"),
|
||||
"groups": ["logged_out"],
|
||||
"action": async () => {
|
||||
_dali.helpers.loading(true);
|
||||
const widget : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.class_widget_login(
|
||||
{
|
||||
"action_cancel": () => {
|
||||
_dali.overlay.clear();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
},
|
||||
"action_success": async () => {
|
||||
_dali.helpers.loading(true);
|
||||
const status = await _dali.backend.status();
|
||||
_dali.notify_login(status.name);
|
||||
// _dali.overlay.clear();
|
||||
_dali.helpers.loading(false);
|
||||
},
|
||||
}
|
||||
);
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
// _dali.helpers.loading(false);
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.caldav.title"),
|
||||
"groups": ["logged_in"],
|
||||
"action": async () => {
|
||||
_dali.helpers.loading(true);
|
||||
const widget : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.class_widget_caldav();
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
// _dali.helpers.loading(false);
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": lib_plankton.translate.get("common.logout"),
|
||||
"groups": ["logged_in"],
|
||||
"action": async () => {
|
||||
_dali.helpers.loading(true);
|
||||
await _dali.logout();
|
||||
_dali.helpers.loading(false);
|
||||
},
|
||||
},
|
||||
]
|
||||
);
|
||||
await widget_menu.load(document.querySelector("header"));
|
||||
_dali.listen_login(
|
||||
async (name) => {
|
||||
widget_menu.set_groups(["logged_in"]);
|
||||
widget_menu.set_label(name);
|
||||
}
|
||||
);
|
||||
_dali.listen_logout(
|
||||
async () => {
|
||||
widget_menu.set_groups(["logged_out"]);
|
||||
widget_menu.set_label(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// process actions
|
||||
{
|
||||
let url_search_params : URLSearchParams = new URLSearchParams(window.location.search);
|
||||
const action : (null | string) = url_search_params.get("action");
|
||||
switch (action)
|
||||
{
|
||||
case "oidc_finish":
|
||||
{
|
||||
try
|
||||
{
|
||||
await _dali.oidc_finish(url_search_params.get("session_key"));
|
||||
}
|
||||
catch (error_)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
document.location = "/";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case null:
|
||||
{
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process status
|
||||
{
|
||||
const status = await _dali.backend.status();
|
||||
lib_plankton.log.info(
|
||||
"dali.status",
|
||||
status
|
||||
);
|
||||
if (status.logged_in)
|
||||
{
|
||||
_dali.notify_login(status.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dali.notify_logout();
|
||||
}
|
||||
}
|
||||
|
||||
// load overview
|
||||
{
|
||||
const widget : lib_plankton.zoo_widget.interface_widget = (
|
||||
new _dali.widgets.class_widget_overview(
|
||||
)
|
||||
);
|
||||
await widget.load(document.querySelector("main"));
|
||||
}
|
||||
_dali.helpers.loading(false);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
692
source/model.ts
692
source/model.ts
|
|
@ -1,692 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.model
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_state = {
|
||||
groups : Array<
|
||||
{
|
||||
id : _dali.type_group_id;
|
||||
object : _dali.type_group_object;
|
||||
}
|
||||
>;
|
||||
users : Array<
|
||||
{
|
||||
id : _dali.type_user_id;
|
||||
name : string;
|
||||
}
|
||||
>;
|
||||
calendars : (
|
||||
null
|
||||
|
|
||||
lib_plankton.map.type_map<
|
||||
_dali.type_calendar_id,
|
||||
{
|
||||
reduced : _dali.type_calendar_object_reduced;
|
||||
complete : (null | _dali.type_calendar_object);
|
||||
}
|
||||
>
|
||||
);
|
||||
events : lib_plankton.map.type_map<
|
||||
_dali.type_event_key,
|
||||
_dali.type_event_object_extended
|
||||
>;
|
||||
covered_dates : lib_plankton.set.type_set<
|
||||
lib_plankton.pit.type_date
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _state : (null | type_state) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _listeners_reset : Array<((priviliged ?: boolean) => Promise<void>)> = [];
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function make_date_set(
|
||||
{
|
||||
"elements": elements = [],
|
||||
}
|
||||
:
|
||||
{
|
||||
elements ?: Array<lib_plankton.pit.type_date>;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: lib_plankton.set.type_set<lib_plankton.pit.type_date>
|
||||
{
|
||||
return lib_plankton.set.hashset.implementation_set(
|
||||
lib_plankton.set.hashset.make(
|
||||
x => lib_plankton.pit.date_format(x),
|
||||
{
|
||||
/**
|
||||
* @todo häääh!?
|
||||
*/
|
||||
"elements": elements.filter(x => (x !== null)),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function timeframe_to_date_set(
|
||||
timeframe : {
|
||||
from : lib_plankton.pit.type_pit;
|
||||
to : lib_plankton.pit.type_pit;
|
||||
}
|
||||
)
|
||||
: lib_plankton.set.type_set<lib_plankton.pit.type_date>
|
||||
{
|
||||
if (! lib_plankton.pit.is_before(timeframe.from, timeframe.to))
|
||||
{
|
||||
throw (new Error("invalid timeframe"));
|
||||
}
|
||||
else
|
||||
{
|
||||
const heuristic : int = Math.ceil((timeframe.to - timeframe.from) / (60 * 60 * 24));
|
||||
let pit_current : lib_plankton.pit.type_pit = timeframe.from;
|
||||
return make_date_set(
|
||||
{
|
||||
"elements": (
|
||||
lib_plankton.list.sequence(heuristic)
|
||||
.map(
|
||||
(offset) => lib_plankton.call.convey(
|
||||
timeframe.from,
|
||||
[
|
||||
x => lib_plankton.pit.shift_day(x, offset),
|
||||
x => lib_plankton.pit.to_datetime(x),
|
||||
x => x.date,
|
||||
]
|
||||
)
|
||||
)
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function group_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
id : _dali.type_group_id;
|
||||
object : _dali.type_group_object;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return Promise.resolve(_state.groups);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function user_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
id : _dali.type_user_id;
|
||||
name : string;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return Promise.resolve(_state.users);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function sync_calendars(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const data = await _dali.backend.calendar_list();
|
||||
lib_plankton.map.clear(_state.calendars);
|
||||
data.forEach(
|
||||
entry => {
|
||||
_state.calendars.set(
|
||||
entry.id,
|
||||
{
|
||||
"reduced": {
|
||||
"name": entry.name,
|
||||
"hue": entry.hue,
|
||||
"access_level": _dali.access_level_decode(entry.access_level),
|
||||
},
|
||||
"complete": null,
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function calendar_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
_dali.type_calendar_object_reduced_with_id
|
||||
>
|
||||
>
|
||||
{
|
||||
return Promise.resolve(
|
||||
lib_plankton.map.dump(_state.calendars)
|
||||
.map(
|
||||
pair => (
|
||||
{
|
||||
"id": pair.key,
|
||||
"name": pair.value.reduced.name,
|
||||
"hue": pair.value.reduced.hue,
|
||||
"access_level": pair.value.reduced.access_level,
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_get(
|
||||
calendar_id : _dali.type_calendar_id
|
||||
)
|
||||
: Promise<_dali.type_calendar_object>
|
||||
{
|
||||
const value = _state.calendars.get(calendar_id);
|
||||
if (value.complete === null)
|
||||
{
|
||||
const data = await _dali.backend.calendar_get(calendar_id);
|
||||
const calendar_object : _dali.type_calendar_object = {
|
||||
"name": data.name,
|
||||
"hue": data.hue,
|
||||
"access": {
|
||||
"public": data.access.public,
|
||||
"default_level": _dali.access_level_decode(data.access.default_level),
|
||||
"attributed_group": lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
x => x.toFixed(0),
|
||||
{
|
||||
"pairs": (
|
||||
data.access.attributed_group
|
||||
.map(
|
||||
(entry) => (
|
||||
{
|
||||
"key": entry.group_id,
|
||||
"value": _dali.access_level_decode(entry.level),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
),
|
||||
"attributed_user": lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
x => x.toFixed(0),
|
||||
{
|
||||
"pairs": (
|
||||
data.access.attributed_user
|
||||
.map(
|
||||
(entry) => (
|
||||
{
|
||||
"key": entry.user_id,
|
||||
"value": _dali.access_level_decode(entry.level),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
),
|
||||
},
|
||||
"resource_id": data.resource_id,
|
||||
};
|
||||
value.complete = calendar_object;
|
||||
/**
|
||||
* @todo set in map?
|
||||
*/
|
||||
return calendar_object;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.complete;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_add(
|
||||
calendar_object : _dali.type_calendar_object
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const calendar_id : _dali.type_calendar_id = await _dali.backend.calendar_add(
|
||||
{
|
||||
"name": calendar_object.name,
|
||||
"hue": calendar_object.hue,
|
||||
"access": {
|
||||
"public": calendar_object.access.public,
|
||||
"default_level": _dali.access_level_encode(calendar_object.access.default_level),
|
||||
"attributed_group": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed_group)
|
||||
.map(
|
||||
(pair) => (
|
||||
{
|
||||
"group_id": pair.key,
|
||||
"level": _dali.access_level_encode(pair.value),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
"attributed_user": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed_user)
|
||||
.map(
|
||||
(pair) => (
|
||||
{
|
||||
"user_id": pair.key,
|
||||
"level": _dali.access_level_encode(pair.value),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
},
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
"resource": {
|
||||
"kind": "local",
|
||||
"data": {
|
||||
"events": [],
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
const calendar_object_reduced : _dali.type_calendar_object_reduced = {
|
||||
"name": calendar_object.name,
|
||||
"hue": calendar_object.hue,
|
||||
"access_level": _dali.enum_access_level.admin,
|
||||
};
|
||||
_state.calendars.set(
|
||||
calendar_id,
|
||||
{
|
||||
"reduced": calendar_object_reduced,
|
||||
"complete": calendar_object,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_change(
|
||||
calendar_id : _dali.type_calendar_id,
|
||||
calendar_object : _dali.type_calendar_object
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
/*await */ _dali.backend.calendar_change(
|
||||
calendar_id,
|
||||
{
|
||||
"name": calendar_object.name,
|
||||
"hue": calendar_object.hue,
|
||||
"access": {
|
||||
"public": calendar_object.access.public,
|
||||
"default_level": _dali.access_level_encode(calendar_object.access.default_level),
|
||||
"attributed_group": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed_group)
|
||||
.map(
|
||||
(pair) => ({
|
||||
"group_id": pair.key,
|
||||
"level": _dali.access_level_encode(pair.value),
|
||||
})
|
||||
)
|
||||
),
|
||||
"attributed_user": (
|
||||
lib_plankton.map.dump(calendar_object.access.attributed_user)
|
||||
.map(
|
||||
(pair) => ({
|
||||
"user_id": pair.key,
|
||||
"level": _dali.access_level_encode(pair.value),
|
||||
})
|
||||
)
|
||||
),
|
||||
},
|
||||
}
|
||||
);
|
||||
const calendar_object_reduced : _dali.type_calendar_object_reduced = {
|
||||
"name": calendar_object.name,
|
||||
"hue": calendar_object.hue,
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
"access_level": _dali.enum_access_level.admin,
|
||||
};
|
||||
_state.calendars.set(
|
||||
calendar_id,
|
||||
{
|
||||
"reduced": calendar_object_reduced,
|
||||
"complete": calendar_object,
|
||||
}
|
||||
);
|
||||
{
|
||||
lib_plankton.map.clear(_state.events);
|
||||
lib_plankton.set.clear(_state.covered_dates);
|
||||
notify_reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_remove(
|
||||
calendar_id : _dali.type_calendar_id
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
/*await */ _dali.backend.calendar_remove(calendar_id);
|
||||
_state.calendars.delete(calendar_id);
|
||||
{
|
||||
lib_plankton.map.clear(_state.events);
|
||||
lib_plankton.set.clear(_state.covered_dates);
|
||||
notify_reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo do NOT export?
|
||||
* @todo clear?
|
||||
* @todo heed calendar_ids
|
||||
* @todo mutex
|
||||
* @todo only update outside timeframe
|
||||
*/
|
||||
export async function sync_events(
|
||||
timeframe : {
|
||||
from : lib_plankton.pit.type_pit;
|
||||
to : lib_plankton.pit.type_pit;
|
||||
},
|
||||
{
|
||||
"calendar_ids": calendar_ids = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
calendar_ids ?: (null | Array<_dali.type_calendar_id>);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const queried_dates : lib_plankton.set.type_set<lib_plankton.pit.type_date> = timeframe_to_date_set(
|
||||
timeframe
|
||||
);
|
||||
const new_dates : lib_plankton.set.type_set<lib_plankton.pit.type_date> = lib_plankton.set.difference(
|
||||
() => make_date_set(),
|
||||
queried_dates,
|
||||
_state.covered_dates
|
||||
);
|
||||
if (lib_plankton.set.empty(new_dates))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const result = await _dali.backend.events(
|
||||
timeframe.from,
|
||||
timeframe.to,
|
||||
{
|
||||
"calendar_ids": calendar_ids,
|
||||
}
|
||||
);
|
||||
result.forEach(
|
||||
entry => {
|
||||
_state.events.set(
|
||||
entry.hash,
|
||||
{
|
||||
"key": entry.hash,
|
||||
"calendar_id": entry.calendar_id,
|
||||
"calendar_name": entry.calendar_name,
|
||||
"hue": entry.hue,
|
||||
"access_level": _dali.access_level_decode(entry.access_level),
|
||||
"event_id": entry.event_id,
|
||||
"event_object": entry.event_object
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
_state.covered_dates = lib_plankton.set.union(
|
||||
() => make_date_set(),
|
||||
_state.covered_dates,
|
||||
new_dates
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function event_list(
|
||||
)
|
||||
: Promise<Array<_dali.type_event_object_extended>>
|
||||
{
|
||||
return Promise.resolve(lib_plankton.map.values(_state.events));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function event_get(
|
||||
event_key : _dali.type_event_key
|
||||
)
|
||||
: Promise<_dali.type_event_object_extended>
|
||||
{
|
||||
return Promise.resolve(_state.events.get(event_key));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function event_add(
|
||||
calendar_id : _dali.type_calendar_id,
|
||||
event_object : _dali.type_event_object
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
/**
|
||||
* @todo do NOT wait?
|
||||
*/
|
||||
const result = await _dali.backend.calendar_event_add(
|
||||
calendar_id,
|
||||
event_object
|
||||
);
|
||||
const event_id : _dali.type_local_resource_event_id = result.local_resource_event_id;
|
||||
const event_key : _dali.type_event_key = result.hash;
|
||||
const value = _state.calendars.get(calendar_id);
|
||||
const calendar_object_reduced : _dali.type_calendar_object_reduced = value.reduced;
|
||||
_state.events.set(
|
||||
event_key,
|
||||
{
|
||||
"key": event_key,
|
||||
"calendar_id": calendar_id,
|
||||
"calendar_name": calendar_object_reduced.name,
|
||||
"hue": calendar_object_reduced.hue,
|
||||
"access_level": calendar_object_reduced.access_level,
|
||||
"event_id": event_id,
|
||||
"event_object": event_object,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function event_change(
|
||||
event_key : _dali.type_event_key,
|
||||
event_object : _dali.type_event_object
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const event_object_extended_old : _dali.type_event_object_extended = _state.events.get(event_key);
|
||||
const event_object_extended_new : _dali.type_event_object_extended = {
|
||||
"key": event_object_extended_old.key,
|
||||
"calendar_id": event_object_extended_old.calendar_id,
|
||||
"calendar_name": event_object_extended_old.calendar_name,
|
||||
"hue": event_object_extended_old.hue,
|
||||
"access_level": event_object_extended_old.access_level,
|
||||
"event_id": event_object_extended_old.event_id,
|
||||
"event_object": event_object,
|
||||
};
|
||||
_state.events.set(
|
||||
event_key,
|
||||
event_object_extended_new
|
||||
);
|
||||
/*await */_dali.backend.calendar_event_change(
|
||||
event_object_extended_old.calendar_id,
|
||||
event_object_extended_old.event_id,
|
||||
event_object
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function event_remove(
|
||||
event_key : _dali.type_event_key
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const event_object_extended : _dali.type_event_object_extended = _state.events.get(event_key);
|
||||
_state.events.delete(event_key);
|
||||
/*await */_dali.backend.calendar_event_remove(
|
||||
event_object_extended.calendar_id,
|
||||
event_object_extended.event_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function listen_reset(
|
||||
action : ((priviliged ?: boolean) => Promise<void>)
|
||||
)
|
||||
: void
|
||||
{
|
||||
_listeners_reset.push(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function notify_reset(
|
||||
priviliged ?: boolean
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
for (const action of _listeners_reset)
|
||||
{
|
||||
await action(priviliged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function initialize(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
_state = {
|
||||
"groups": [],
|
||||
"users": [],
|
||||
"calendars": lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
calendar_id => calendar_id.toFixed(0)
|
||||
)
|
||||
),
|
||||
"events": lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
event_key => event_key
|
||||
)
|
||||
),
|
||||
"covered_dates": make_date_set(
|
||||
),
|
||||
};
|
||||
|
||||
_dali.listen_login(
|
||||
async () => {
|
||||
_state.groups = (
|
||||
(await _dali.backend.group_list())
|
||||
.map(
|
||||
entry => (
|
||||
{
|
||||
"id": entry.id,
|
||||
"object": {
|
||||
"name": entry.name,
|
||||
"label": entry.label,
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
_state.users = await _dali.backend.user_list();
|
||||
await sync_calendars();
|
||||
lib_plankton.map.clear(_state.events);
|
||||
lib_plankton.set.clear(_state.covered_dates);
|
||||
notify_reset(true);
|
||||
}
|
||||
);
|
||||
_dali.listen_logout(
|
||||
async () => {
|
||||
_state.groups = [];
|
||||
_state.users = [];
|
||||
await sync_calendars();
|
||||
lib_plankton.map.clear(_state.events);
|
||||
lib_plankton.set.clear(_state.covered_dates);
|
||||
notify_reset(false);
|
||||
}
|
||||
);
|
||||
|
||||
await sync_calendars();
|
||||
// await sync_events();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.overlay
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
function get_container_element(
|
||||
)
|
||||
: HTMLElement
|
||||
{
|
||||
return document.querySelector("#overlay");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function get_content_element(
|
||||
)
|
||||
: HTMLElement
|
||||
{
|
||||
return document.querySelector("#overlay_content");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function clear(
|
||||
)
|
||||
: void
|
||||
{
|
||||
get_content_element().innerHTML = "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function toggle(
|
||||
{
|
||||
"mode": mode = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
mode ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: void
|
||||
{
|
||||
get_container_element().classList.toggle("overlay_active", mode ?? undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function initialize(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
clear();
|
||||
const container_element : HTMLElement = get_container_element();
|
||||
/*
|
||||
container_element.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
if (event.target == container_element)
|
||||
{
|
||||
toggle({"mode": false});
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
119
source/pages/caldav/logic.ts
Normal file
119
source/pages/caldav/logic.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"caldav",
|
||||
async (parameters, target_element) => {
|
||||
target_element.innerHTML = "";
|
||||
const conf = await _zeitbild.frontend_web.backend.user_dav_conf();
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"main",
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.caldav.title"),
|
||||
"content": (
|
||||
(conf === null)
|
||||
?
|
||||
await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"unavailable",
|
||||
{
|
||||
"text": lib_plankton.translate.get("page.caldav.unavailable"),
|
||||
}
|
||||
)
|
||||
:
|
||||
await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"available",
|
||||
{
|
||||
"conf_title": lib_plankton.translate.get("page.caldav.conf.title"),
|
||||
"conf_content": (
|
||||
(conf.password === null)
|
||||
?
|
||||
await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"conf-token_unset",
|
||||
{
|
||||
"text": lib_plankton.translate.get("page.caldav.conf.token_unset")
|
||||
}
|
||||
)
|
||||
:
|
||||
await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"conf-token_set",
|
||||
{
|
||||
"address_label": lib_plankton.translate.get("page.caldav.conf.address"),
|
||||
"address_value": conf.address,
|
||||
"username_label": lib_plankton.translate.get("page.caldav.conf.username"),
|
||||
"username_value": conf.username,
|
||||
"password_label": lib_plankton.translate.get("page.caldav.conf.password"),
|
||||
"password_value": conf.password,
|
||||
"setup_hints_label": lib_plankton.translate.get("page.caldav.conf.setup_hints"),
|
||||
"setup_hint_entries": (
|
||||
await lib_plankton.call.promise_condense<string, unknown>(
|
||||
conf.setup_hints
|
||||
.map(
|
||||
entry => () => _zeitbild.frontend_web.helpers.template_coin(
|
||||
"caldav",
|
||||
"conf-setup_hint_entry",
|
||||
{
|
||||
"text": entry.label,
|
||||
"href": entry.link,
|
||||
"remark": (
|
||||
(entry.remark === null)
|
||||
?
|
||||
""
|
||||
:
|
||||
lib_plankton.string.coin(
|
||||
" — {{content}}",
|
||||
{
|
||||
"content": entry.remark,
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
).join("")
|
||||
}
|
||||
)
|
||||
),
|
||||
"set_token_title": lib_plankton.translate.get("page.caldav.set_token.title"),
|
||||
"set_token_action": (
|
||||
(conf.password === null)
|
||||
?
|
||||
lib_plankton.translate.get("page.caldav.set_token.action.set")
|
||||
:
|
||||
lib_plankton.translate.get("page.caldav.set_token.action.overwrite")
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* logic: set token
|
||||
*/
|
||||
{
|
||||
if (conf !== null)
|
||||
{
|
||||
document.querySelector("#caldav-set_token > button").addEventListener(
|
||||
"click",
|
||||
async () => {
|
||||
await _zeitbild.frontend_web.backend.user_dav_token();
|
||||
lib_plankton.zoo_page.reload();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<div class="widget-caldav-conf">
|
||||
<div id="caldav-conf">
|
||||
<h3>{{conf_title}}</h3>
|
||||
{{conf_content}}
|
||||
</div>
|
||||
<div class="widget-caldav-set_token">
|
||||
<div id="caldav-set_token">
|
||||
<h3>{{set_token_title}}</h3>
|
||||
<button>{{set_token_action}}</button>
|
||||
</div>
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
<li class="widget-caldav-conf-setup_hints-entry">
|
||||
<li class="caldav-conf-setup_hints-entry">
|
||||
<a target="_blank" href="{{href}}">{{text}}</a>{{remark}}
|
||||
</li>
|
||||
18
source/pages/caldav/templates/conf-token_set.html.tpl
Normal file
18
source/pages/caldav/templates/conf-token_set.html.tpl
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<div class="caldav-conf-section" id="caldav-conf-address">
|
||||
<span class="caldav-conf-section-label">{{address_label}}</span>
|
||||
<span class="caldav-conf-section-value caldav-conf-section-value-regular">{{address_value}}</span>
|
||||
</div>
|
||||
<div class="caldav-conf-section" id="caldav-conf-username">
|
||||
<span class="caldav-conf-section-label">{{username_label}}</span>
|
||||
<span class="caldav-conf-section-value caldav-conf-section-value-regular">{{username_value}}</span>
|
||||
</div>
|
||||
<div class="caldav-conf-section" id="caldav-conf-password">
|
||||
<span class="caldav-conf-section-label">{{password_label}}</span>
|
||||
<span class="caldav-conf-section-value caldav-conf-section-value-regular">{{password_value}}</span>
|
||||
</div>
|
||||
<div class="caldav-conf-section" id="caldav-conf-setup_hints">
|
||||
<span class="caldav-conf-section-label">{{setup_hints_label}}</span>
|
||||
<ul>
|
||||
{{setup_hint_entries}}
|
||||
</ul>
|
||||
</div>
|
||||
4
source/pages/caldav/templates/conf-token_unset.html.tpl
Normal file
4
source/pages/caldav/templates/conf-token_unset.html.tpl
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<div id="caldav-conf-info">
|
||||
({{text}})
|
||||
</div>
|
||||
|
||||
6
source/pages/caldav/templates/main.html.tpl
Normal file
6
source/pages/caldav/templates/main.html.tpl
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<div id="caldav">
|
||||
<h2>{{label}}</h2>
|
||||
<div id="caldav-content">
|
||||
{{content}}
|
||||
</div>
|
||||
</div>
|
||||
3
source/pages/caldav/templates/unavailable.html.tpl
Normal file
3
source/pages/caldav/templates/unavailable.html.tpl
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<div id="caldav-info">
|
||||
{{text}}
|
||||
</div>
|
||||
168
source/pages/calendar_add/logic.ts
Normal file
168
source/pages/calendar_add/logic.ts
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"calendar_add",
|
||||
async (parameters, target_element) => {
|
||||
target_element.innerHTML = "";
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"calendar_add",
|
||||
"default",
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.calendar_add.title")
|
||||
}
|
||||
);
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.calendar_object,
|
||||
{
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
attributed : lib_plankton.map.type_map<
|
||||
_zeitbild.frontend_web.type.user_id,
|
||||
_zeitbild.frontend_web.type.enum_access_level
|
||||
>;
|
||||
};
|
||||
resource_kind : string;
|
||||
}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.calendar_object,
|
||||
{
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
attributed : lib_plankton.map.type_map<
|
||||
_zeitbild.frontend_web.type.user_id,
|
||||
_zeitbild.frontend_web.type.enum_access_level
|
||||
>;
|
||||
};
|
||||
resource_kind : string;
|
||||
}
|
||||
>(
|
||||
(calendar_object) => ({
|
||||
"name": calendar_object.name,
|
||||
"access": calendar_object.access,
|
||||
"resource_kind": calendar_object.resource.kind,
|
||||
}),
|
||||
(raw) => ({
|
||||
"name": raw.name,
|
||||
"access": raw.access,
|
||||
"resource": (() => {
|
||||
switch (raw.resource_kind) {
|
||||
case "local": {
|
||||
return {
|
||||
"kind": "local",
|
||||
"data": {
|
||||
"events": [],
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "caldav": {
|
||||
return {
|
||||
"kind": "caldav",
|
||||
"data": {
|
||||
"url": "", // TODO
|
||||
"read_only": true, // TODO
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw (new Error("invalid resource kind: " + raw.resource_kind));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}) (),
|
||||
}),
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(),
|
||||
"label": lib_plankton.translate.get("calendar.name")
|
||||
},
|
||||
{
|
||||
"name": "access",
|
||||
"input": new lib_plankton.zoo_input.class_input_group(
|
||||
[
|
||||
{
|
||||
"name": "public",
|
||||
"input": new lib_plankton.zoo_input.class_input_checkbox(),
|
||||
"label": lib_plankton.translate.get("calendar.access.public"),
|
||||
},
|
||||
{
|
||||
"name": "default_level",
|
||||
"input": _zeitbild.frontend_web.helpers.input_access_level(),
|
||||
"label": lib_plankton.translate.get("calendar.access.default_level"),
|
||||
},
|
||||
{
|
||||
"name": "attributed",
|
||||
"input": await _zeitbild.frontend_web.helpers.input_attributed_access(),
|
||||
"label": lib_plankton.translate.get("calendar.access.attributed"),
|
||||
},
|
||||
]
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.access.access"),
|
||||
},
|
||||
{
|
||||
"name": "resource_kind",
|
||||
"input": new lib_plankton.zoo_input.class_input_selection(
|
||||
[
|
||||
{
|
||||
"value": "local",
|
||||
"label": lib_plankton.translate.get("resource.kinds.local.title")
|
||||
},
|
||||
{
|
||||
"value": "caldav",
|
||||
"label": lib_plankton.translate.get("resource.kinds.caldav.title")
|
||||
},
|
||||
]
|
||||
),
|
||||
"label": lib_plankton.translate.get("resource.kind")
|
||||
},
|
||||
]
|
||||
),
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.calendar_add.actions.do"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_add(
|
||||
value
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
await form.setup(document.querySelector("#calendar_add_form"));
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
5
source/pages/calendar_add/templates/default.html.tpl
Normal file
5
source/pages/calendar_add/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div id="calendar_add">
|
||||
<h2>{{label}}</h2>
|
||||
<div id="calendar_add_form">
|
||||
</div>
|
||||
</div>
|
||||
171
source/pages/calendar_edit/logic.ts
Normal file
171
source/pages/calendar_edit/logic.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"calendar_edit",
|
||||
async (parameters, target_element) => {
|
||||
const read_only : boolean = ((parameters["read_only"] ?? "yes") === "yes");
|
||||
const calendar_id : int = parseInt(parameters["calendar_id"]);
|
||||
target_element.innerHTML = "";
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"calendar_edit",
|
||||
"default",
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.calendar_edit.title.regular")
|
||||
}
|
||||
);
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.calendar_object,
|
||||
{
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
attributed : lib_plankton.map.type_map<
|
||||
_zeitbild.frontend_web.type.user_id,
|
||||
_zeitbild.frontend_web.type.enum_access_level
|
||||
>;
|
||||
};
|
||||
}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.calendar_object,
|
||||
{
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
attributed : lib_plankton.map.type_map<
|
||||
_zeitbild.frontend_web.type.user_id,
|
||||
_zeitbild.frontend_web.type.enum_access_level
|
||||
>;
|
||||
};
|
||||
}
|
||||
>(
|
||||
(calendar_object) => ({
|
||||
"name": calendar_object.name,
|
||||
"access": calendar_object.access,
|
||||
}),
|
||||
(raw) => ({
|
||||
"name": raw.name,
|
||||
"access": raw.access,
|
||||
"resource": {
|
||||
"kind": "local",
|
||||
"data": {
|
||||
"events": [],
|
||||
}
|
||||
},
|
||||
}),
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(),
|
||||
"label": lib_plankton.translate.get("calendar.name")
|
||||
},
|
||||
{
|
||||
"name": "access",
|
||||
"input": new lib_plankton.zoo_input.class_input_group(
|
||||
[
|
||||
{
|
||||
"name": "public",
|
||||
"input": new lib_plankton.zoo_input.class_input_checkbox(),
|
||||
"label": lib_plankton.translate.get("calendar.access.public"),
|
||||
},
|
||||
{
|
||||
"name": "default_level",
|
||||
"input": _zeitbild.frontend_web.helpers.input_access_level(),
|
||||
"label": lib_plankton.translate.get("calendar.access.default_level"),
|
||||
},
|
||||
{
|
||||
"name": "attributed",
|
||||
"input": await _zeitbild.frontend_web.helpers.input_attributed_access(),
|
||||
"label": lib_plankton.translate.get("calendar.access.attributed"),
|
||||
},
|
||||
]
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.access.access"),
|
||||
},
|
||||
]
|
||||
),
|
||||
(
|
||||
read_only
|
||||
?
|
||||
[
|
||||
]
|
||||
:
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.calendar_edit.actions.change"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_change(
|
||||
calendar_id,
|
||||
value
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.calendar_edit.actions.remove"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_remove(
|
||||
calendar_id
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
);
|
||||
await form.setup(document.querySelector("#calendar_edit_form"));
|
||||
const calendar_object : _zeitbild.frontend_web.type.calendar_object = await _zeitbild.frontend_web.backend.calendar_get(
|
||||
calendar_id
|
||||
);
|
||||
await form.input_write(calendar_object);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
5
source/pages/calendar_edit/templates/default.html.tpl
Normal file
5
source/pages/calendar_edit/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div id="calendar_edit">
|
||||
<h2>{{label}}</h2>
|
||||
<div id="calendar_edit_form">
|
||||
</div>
|
||||
</div>
|
||||
235
source/pages/event_add/logic.ts
Normal file
235
source/pages/event_add/logic.ts
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"event_add",
|
||||
async (parameters, target_element) => {
|
||||
const calendar_id : (null | int) = (
|
||||
("calendar_id" in parameters)
|
||||
?
|
||||
parseInt(parameters["calendar_id"])
|
||||
:
|
||||
null
|
||||
);
|
||||
const year : (null | int) = (
|
||||
("year" in parameters)
|
||||
?
|
||||
parseInt(parameters["year"])
|
||||
:
|
||||
null
|
||||
);
|
||||
const month : (null | int) = (
|
||||
("month" in parameters)
|
||||
?
|
||||
parseInt(parameters["month"])
|
||||
:
|
||||
null
|
||||
);
|
||||
const day : (null | int) = (
|
||||
("day" in parameters)
|
||||
?
|
||||
parseInt(parameters["day"])
|
||||
:
|
||||
null
|
||||
);
|
||||
const date : lib_plankton.pit.type_date = (
|
||||
(
|
||||
(year !== null)
|
||||
&&
|
||||
(month !== null)
|
||||
&&
|
||||
(day !== null)
|
||||
)
|
||||
?
|
||||
{
|
||||
"year": year,
|
||||
"month": month,
|
||||
"day": day,
|
||||
}
|
||||
:
|
||||
lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date
|
||||
);
|
||||
target_element.innerHTML = "";
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"event_add",
|
||||
"default",
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.event_add.title")
|
||||
}
|
||||
);
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
{
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id;
|
||||
event_object : _zeitbild.frontend_web.type.event_object;
|
||||
},
|
||||
{
|
||||
calendar_id : string;
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (null | lib_plankton.pit.type_datetime);
|
||||
location : (null | string);
|
||||
link : (null | string);
|
||||
description : (null | string);
|
||||
}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
{
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id;
|
||||
event_object : _zeitbild.frontend_web.type.event_object;
|
||||
},
|
||||
{
|
||||
calendar_id : string;
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (null | lib_plankton.pit.type_datetime);
|
||||
location : (null | string);
|
||||
link : (null | string);
|
||||
description : (null | string);
|
||||
}
|
||||
>(
|
||||
(value) => ({
|
||||
"calendar_id": value.calendar_id.toFixed(0),
|
||||
"name": value.event_object.name,
|
||||
"begin": value.event_object.begin,
|
||||
"end": value.event_object.end,
|
||||
"location": value.event_object.location,
|
||||
"link": value.event_object.link,
|
||||
"description": value.event_object.description,
|
||||
}),
|
||||
(representation) => ({
|
||||
"calendar_id": parseInt(representation.calendar_id),
|
||||
"event_object": {
|
||||
"name": representation.name,
|
||||
"begin": representation.begin,
|
||||
"end": representation.end,
|
||||
"location": representation.location,
|
||||
"link": representation.link,
|
||||
"description": representation.description,
|
||||
}
|
||||
}),
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "calendar_id",
|
||||
"input": new lib_plankton.zoo_input.class_input_selection(
|
||||
(
|
||||
(await _zeitbild.frontend_web.backend.calendar_list())
|
||||
.filter(
|
||||
(entry) => (
|
||||
(entry.access_level === _zeitbild.frontend_web.type.enum_access_level.edit)
|
||||
||
|
||||
(entry.access_level === _zeitbild.frontend_web.type.enum_access_level.admin)
|
||||
)
|
||||
)
|
||||
.map(
|
||||
(entry) => ({
|
||||
"value": entry.id.toFixed(0),
|
||||
"label": entry.name,
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.calendar")
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.name")
|
||||
},
|
||||
{
|
||||
"name": "begin",
|
||||
"input": _zeitbild.frontend_web.helpers.datetime_input(),
|
||||
"label": lib_plankton.translate.get("event.begin")
|
||||
},
|
||||
{
|
||||
"name": "end",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
|
||||
_zeitbild.frontend_web.helpers.datetime_input()
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.end")
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.location")
|
||||
},
|
||||
{
|
||||
"name": "link",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.link")
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_textarea(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.description")
|
||||
},
|
||||
]
|
||||
),
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.event_add.actions.do"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_event_add(
|
||||
value.calendar_id,
|
||||
value.event_object
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
await form.setup(document.querySelector("#event_add_form"));
|
||||
await form.input_write(
|
||||
{
|
||||
"calendar_id": (calendar_id ?? 0),
|
||||
"event_object": {
|
||||
"name": "",
|
||||
"begin": {
|
||||
"timezone_shift": 0,
|
||||
"date": date,
|
||||
"time": null
|
||||
},
|
||||
"end": null,
|
||||
"location": null,
|
||||
"link": null,
|
||||
"description": null,
|
||||
}
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
5
source/pages/event_add/templates/default.html.tpl
Normal file
5
source/pages/event_add/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div id="event_add">
|
||||
<h2>{{label}}</h2>
|
||||
<div id="event_add_form">
|
||||
</div>
|
||||
</div>
|
||||
195
source/pages/event_edit/logic.ts
Normal file
195
source/pages/event_edit/logic.ts
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"event_edit",
|
||||
async (parameters, target_element) => {
|
||||
const read_only : boolean = ((parameters["read_only"] ?? "yes") === "yes");
|
||||
const calendar_id : int = parseInt(parameters["calendar_id"]);
|
||||
const event_id : int = parseInt(parameters["event_id"]);
|
||||
target_element.innerHTML = "";
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"event_edit",
|
||||
"default",
|
||||
{
|
||||
"label": (
|
||||
read_only
|
||||
?
|
||||
lib_plankton.translate.get("page.event_edit.title.read_only")
|
||||
:
|
||||
lib_plankton.translate.get("page.event_edit.title.regular")
|
||||
)
|
||||
}
|
||||
);
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.event_object,
|
||||
{
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (null | lib_plankton.pit.type_datetime);
|
||||
location : (null | string);
|
||||
link : (null | string);
|
||||
description : (null | string);
|
||||
}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
_zeitbild.frontend_web.type.event_object,
|
||||
{
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (null | lib_plankton.pit.type_datetime);
|
||||
location : (null | string);
|
||||
link : (null | string);
|
||||
description : (null | string);
|
||||
}
|
||||
>(
|
||||
(value) => ({
|
||||
"name": value.name,
|
||||
"begin": value.begin,
|
||||
"end": value.end,
|
||||
"location": value.location,
|
||||
"link": value.link,
|
||||
"description": value.description,
|
||||
}),
|
||||
(representation) => ({
|
||||
"name": representation.name,
|
||||
"begin": representation.begin,
|
||||
"end": representation.end,
|
||||
"location": representation.location,
|
||||
"link": representation.link,
|
||||
"description": representation.description,
|
||||
}),
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.name")
|
||||
},
|
||||
{
|
||||
"name": "begin",
|
||||
"input": _zeitbild.frontend_web.helpers.datetime_input(),
|
||||
"label": lib_plankton.translate.get("event.begin")
|
||||
},
|
||||
{
|
||||
"name": "end",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
|
||||
_zeitbild.frontend_web.helpers.datetime_input()
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.end")
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.location")
|
||||
},
|
||||
{
|
||||
"name": "link",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.link")
|
||||
},
|
||||
{
|
||||
"name": "description",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_textarea(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.description")
|
||||
},
|
||||
]
|
||||
),
|
||||
(
|
||||
read_only
|
||||
?
|
||||
[
|
||||
]
|
||||
:
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.event_edit.actions.change"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_event_change(
|
||||
calendar_id,
|
||||
event_id,
|
||||
value
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
lib_plankton.log.warning("page_event_edit_error", {"error": String(error)});
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.event_edit.actions.remove"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.calendar_event_remove(
|
||||
calendar_id,
|
||||
event_id
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
lib_plankton.log.warning("page_event_edit_error", {"error": String(error)});
|
||||
// do nothing
|
||||
/*
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
);
|
||||
await form.setup(document.querySelector("#event_edit_form"));
|
||||
const event_object : _zeitbild.frontend_web.type.event_object = await _zeitbild.frontend_web.backend.calendar_event_get(
|
||||
calendar_id,
|
||||
event_id
|
||||
);
|
||||
await form.input_write(
|
||||
event_object
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
5
source/pages/event_edit/templates/default.html.tpl
Normal file
5
source/pages/event_edit/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<div id="event_edit">
|
||||
<h2>{{label}}</h2>
|
||||
<div id="event_edit_form">
|
||||
</div>
|
||||
</div>
|
||||
111
source/pages/login/logic.ts
Normal file
111
source/pages/login/logic.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"login",
|
||||
async (parameters, target_element) => {
|
||||
target_element.innerHTML = "";
|
||||
const preparation : {kind : string; data : any;} = await _zeitbild.frontend_web.backend.session_prepare(
|
||||
{
|
||||
"oidc_redirect_uri_template": _zeitbild.frontend_web.conf.get()["misc"]["oidc_redirect_uri_template"],
|
||||
}
|
||||
);
|
||||
switch (preparation.kind) {
|
||||
case "internal": {
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"login",
|
||||
"default",
|
||||
{
|
||||
}
|
||||
);
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
{name : string; password : string;},
|
||||
{name : string; password : string;}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
{name : string; password : string;},
|
||||
{name : string; password : string;}
|
||||
>(
|
||||
x => x,
|
||||
x => x,
|
||||
new lib_plankton.zoo_input.class_input_group<
|
||||
{name : string; password : string;}
|
||||
>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(),
|
||||
"label": lib_plankton.translate.get("page.login.internal.name"),
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"input": new lib_plankton.zoo_input.class_input_password(),
|
||||
"label": lib_plankton.translate.get("page.login.internal.password"),
|
||||
},
|
||||
]
|
||||
),
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("page.login.internal.do"),
|
||||
"target": "submit",
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try {
|
||||
await _zeitbild.frontend_web.backend.session_begin(
|
||||
value.name,
|
||||
value.password
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (error) {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "login",
|
||||
"parameters": {
|
||||
"name": value.name,
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
);
|
||||
await form.setup(document.querySelector("#login"));
|
||||
await form.input_write(
|
||||
{
|
||||
"name": (parameters.name ?? ""),
|
||||
"password": "",
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "oidc": {
|
||||
let element_a : HTMLElement = document.createElement("a");;
|
||||
element_a.textContent = lib_plankton.string.coin(
|
||||
lib_plankton.translate.get("page.login.oidc.via"),
|
||||
{
|
||||
"title": preparation.data.label,
|
||||
}
|
||||
);
|
||||
element_a.setAttribute("href", preparation.data.url);
|
||||
target_element.innerHTML = "";
|
||||
target_element.appendChild(element_a);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
2
source/pages/login/templates/default.html.tpl
Normal file
2
source/pages/login/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<div id="login">
|
||||
</div>
|
||||
23
source/pages/logout/logic.ts
Normal file
23
source/pages/logout/logic.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"logout",
|
||||
async (parameters, target_element) => {
|
||||
target_element.innerHTML = "";
|
||||
await _zeitbild.frontend_web.backend.session_end(
|
||||
);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {
|
||||
}
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
21
source/pages/oidc_finish/logic.ts
Normal file
21
source/pages/oidc_finish/logic.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
namespace _zeitbild.frontend_web.pages
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"oidc_finish",
|
||||
async (parameters, target_element) => {
|
||||
target_element.innerHTML = "";
|
||||
await _zeitbild.frontend_web.backend.set_session_key(parameters["session_key"]);
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "overview",
|
||||
"parameters": {}
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
197
source/pages/overview/logic.ts
Normal file
197
source/pages/overview/logic.ts
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
namespace _zeitbild.frontend_web.pages.overview
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
lib_plankton.zoo_page.register(
|
||||
"overview",
|
||||
async (parameters, target_element) => {
|
||||
// params
|
||||
const compact : boolean = (
|
||||
(
|
||||
parameters["compact"]
|
||||
??
|
||||
(
|
||||
(window.innerWidth >= 800)
|
||||
?
|
||||
"no"
|
||||
:
|
||||
"yes"
|
||||
)
|
||||
)
|
||||
===
|
||||
"yes"
|
||||
);
|
||||
|
||||
// exec
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"overview",
|
||||
"default",
|
||||
{
|
||||
}
|
||||
);
|
||||
target_element.querySelector("#overview").classList.toggle("overview-compact", compact);
|
||||
let widget_weekview : _zeitbild.frontend_web.widgets.weekview.class_widget_weekview;
|
||||
let widget_listview : _zeitbild.frontend_web.widgets.listview.class_widget_listview;
|
||||
// hint
|
||||
{
|
||||
if (! await _zeitbild.frontend_web.backend.is_logged_in()) {
|
||||
target_element.querySelector("#overview-head").textContent = lib_plankton.translate.get("page.overview.login_hint");
|
||||
}
|
||||
else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
// sources
|
||||
{
|
||||
const data : Array<
|
||||
{
|
||||
id : _zeitbild.frontend_web.type.calendar_id;
|
||||
name : string;
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
}
|
||||
> = await _zeitbild.frontend_web.backend.calendar_list(
|
||||
);
|
||||
const widget_sources = new _zeitbild.frontend_web.widgets.sources.class_widget_sources(
|
||||
data,
|
||||
{
|
||||
"action_open": (entry) => {
|
||||
switch (entry.access_level) {
|
||||
case _zeitbild.frontend_web.type.enum_access_level.none: {
|
||||
throw (new Error("this event should not be visible"));
|
||||
break;
|
||||
}
|
||||
case _zeitbild.frontend_web.type.enum_access_level.edit:
|
||||
case _zeitbild.frontend_web.type.enum_access_level.view: {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "calendar_edit",
|
||||
"parameters": {
|
||||
"read_only": "yes",
|
||||
"calendar_id": entry.id,
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case _zeitbild.frontend_web.type.enum_access_level.admin: {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "calendar_edit",
|
||||
"parameters": {
|
||||
"read_only": "no",
|
||||
"calendar_id": entry.id,
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"action_toggle_visibility": (entry) => {
|
||||
widget_weekview.toggle_visibility(entry.id);
|
||||
},
|
||||
}
|
||||
);
|
||||
await widget_sources.load(target_element.querySelector("#overview-pane-left"));
|
||||
}
|
||||
// events
|
||||
{
|
||||
const get_entries = (from_pit, to_pit, calendar_ids) => _zeitbild.frontend_web.backend.events(
|
||||
from_pit,
|
||||
to_pit,
|
||||
{
|
||||
"calendar_ids": calendar_ids,
|
||||
}
|
||||
);
|
||||
const action_select_event = (calendar_id, access_level, event_id) => {
|
||||
switch (access_level) {
|
||||
case _zeitbild.frontend_web.type.enum_access_level.none: {
|
||||
throw (new Error("this event should not be visible"));
|
||||
break;
|
||||
}
|
||||
case _zeitbild.frontend_web.type.enum_access_level.view: {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_edit",
|
||||
"parameters": {
|
||||
"read_only": "yes",
|
||||
"calendar_id": calendar_id,
|
||||
"event_id": event_id,
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case _zeitbild.frontend_web.type.enum_access_level.edit:
|
||||
case _zeitbild.frontend_web.type.enum_access_level.admin: {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_edit",
|
||||
"parameters": {
|
||||
"read_only": "no",
|
||||
"calendar_id": calendar_id,
|
||||
"event_id": event_id,
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
// listview
|
||||
{
|
||||
widget_listview = (
|
||||
new _zeitbild.frontend_web.widgets.listview.class_widget_listview(
|
||||
get_entries,
|
||||
{
|
||||
"action_select_event": action_select_event,
|
||||
"action_add": () => {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
"calendar_id": null,
|
||||
"year": null,
|
||||
"month": null,
|
||||
"day": null,
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
await widget_listview.load(target_element.querySelector("#overview-pane-right-listview"));
|
||||
}
|
||||
// weekview
|
||||
{
|
||||
widget_weekview = (
|
||||
new _zeitbild.frontend_web.widgets.weekview.class_widget_weekview(
|
||||
get_entries,
|
||||
{
|
||||
"action_select_event": action_select_event,
|
||||
"action_select_day": (date) => {
|
||||
lib_plankton.zoo_page.set(
|
||||
{
|
||||
"name": "event_add",
|
||||
"parameters": {
|
||||
"calendar_id": null,
|
||||
"year": date.year,
|
||||
"month": date.month,
|
||||
"day": date.day,
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
await widget_weekview.load(target_element.querySelector("#overview-pane-right-weekview"));
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
14
source/pages/overview/templates/default.html.tpl
Normal file
14
source/pages/overview/templates/default.html.tpl
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<div id="overview">
|
||||
<div id="overview-head">
|
||||
</div>
|
||||
<div id="overview-body">
|
||||
<div id="overview-pane-left">
|
||||
</div>
|
||||
<div id="overview-pane-right">
|
||||
<div id="overview-pane-right-weekview">
|
||||
</div>
|
||||
<div id="overview-pane-right-listview">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,799 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
namespace _dali.backend
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_conf = {
|
||||
scheme : string;
|
||||
host : string;
|
||||
port : int;
|
||||
path : string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_request = {
|
||||
method : lib_plankton.http.enum_method;
|
||||
action : string;
|
||||
input : (null | any);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_event_object = {
|
||||
name : string;
|
||||
begin : {
|
||||
timezone_shift: int;
|
||||
date: {
|
||||
year: int;
|
||||
month: int;
|
||||
day: int;
|
||||
};
|
||||
time: (
|
||||
null
|
||||
|
|
||||
{
|
||||
hour: int;
|
||||
minute: int;
|
||||
second: int;
|
||||
}
|
||||
);
|
||||
};
|
||||
end : (
|
||||
null
|
||||
|
|
||||
{
|
||||
timezone_shift: int;
|
||||
date: {
|
||||
year: int;
|
||||
month: int;
|
||||
day: int;
|
||||
};
|
||||
time: (
|
||||
null
|
||||
|
|
||||
{
|
||||
hour: int;
|
||||
minute: int;
|
||||
second: int;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
location : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
link : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
description : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _conf : type_conf;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _data_chest : (
|
||||
null
|
||||
|
|
||||
lib_plankton.storage.type_chest<string, string, void, string, string>
|
||||
) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _cache : (
|
||||
null
|
||||
|
|
||||
lib_plankton.cache.type_subject<boolean>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _queue : lib_plankton.call.type_queue<type_request, any>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function initialize(
|
||||
conf : type_conf
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
_conf = conf;
|
||||
_data_chest = lib_plankton.storage.localstorage.implementation_chest(
|
||||
{
|
||||
"corner": "zeitbild",
|
||||
}
|
||||
);
|
||||
_cache = lib_plankton.cache.make<boolean>(
|
||||
/*
|
||||
lib_plankton.storage.memory.implementation_chest(
|
||||
{
|
||||
}
|
||||
)
|
||||
*/
|
||||
);
|
||||
_queue = lib_plankton.call.queue_make<type_request, any>(
|
||||
call_real
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function get_session_key(
|
||||
)
|
||||
: Promise<(null | string)>
|
||||
{
|
||||
try
|
||||
{
|
||||
return (await _data_chest.read("session_key"));
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function call_real(
|
||||
request : type_request
|
||||
)
|
||||
: Promise<any>
|
||||
{
|
||||
const with_body : boolean = (
|
||||
[
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.http.enum_method.patch,
|
||||
].includes(request.method)
|
||||
);
|
||||
const session_key : (null | string) = await get_session_key();
|
||||
const http_request : lib_plankton.http.type_request = {
|
||||
"version": "HTTP/2",
|
||||
"scheme": (
|
||||
(_conf.scheme === "http")
|
||||
?
|
||||
"http"
|
||||
:
|
||||
"https"
|
||||
),
|
||||
"host": lib_plankton.string.coin(
|
||||
"{{host}}:{{port}}",
|
||||
{
|
||||
"host": _conf.host,
|
||||
"port": _conf.port.toFixed(0),
|
||||
}
|
||||
),
|
||||
"path": lib_plankton.string.coin(
|
||||
"{{base}}{{action}}",
|
||||
{
|
||||
"base": _conf.path,
|
||||
"action": request.action,
|
||||
}
|
||||
),
|
||||
"method": request.method,
|
||||
"query": (
|
||||
(with_body || (request.input === null))
|
||||
?
|
||||
null
|
||||
:
|
||||
("?" + lib_plankton.www_form.encode(request.input))
|
||||
),
|
||||
"headers": Object.assign(
|
||||
{},
|
||||
(
|
||||
(! with_body)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"Content-Type": "application/json"}
|
||||
),
|
||||
(
|
||||
(session_key === null)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"X-Session-Key": session_key}
|
||||
)
|
||||
),
|
||||
"body": (
|
||||
((! with_body) || (request.input === null))
|
||||
?
|
||||
null
|
||||
:
|
||||
/*Buffer.from*/(lib_plankton.json.encode(request.input))
|
||||
),
|
||||
};
|
||||
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(http_request);
|
||||
if (
|
||||
! (
|
||||
(http_response.status_code >= 200)
|
||||
&&
|
||||
(http_response.status_code < 300)
|
||||
)
|
||||
)
|
||||
{
|
||||
return Promise.reject<any>(http_response.body.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
const output : any = lib_plankton.json.decode(http_response.body.toString());
|
||||
return Promise.resolve<any>(output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function call(
|
||||
method : lib_plankton.http.enum_method,
|
||||
action : string,
|
||||
input : (null | any)
|
||||
)
|
||||
: Promise<any>
|
||||
{
|
||||
const request : type_request = {
|
||||
"method": method,
|
||||
"action": action,
|
||||
"input": input,
|
||||
};
|
||||
return (
|
||||
new Promise<any>(
|
||||
(resolve, reject) => {
|
||||
lib_plankton.call.queue_add<type_request, any>(
|
||||
_queue,
|
||||
request,
|
||||
resolve,
|
||||
reject
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function status(
|
||||
)
|
||||
: Promise<
|
||||
{
|
||||
logged_in : boolean;
|
||||
name : (null | string);
|
||||
}
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/session/status",
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_prepare(
|
||||
input : any
|
||||
)
|
||||
: Promise<{kind : string; data : any;}>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
"/session/prepare",
|
||||
input
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function set_session_key(
|
||||
session_key : string
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
return (
|
||||
_data_chest.write("session_key", session_key)
|
||||
.then<void>(() => Promise.resolve<void>(undefined))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_begin(
|
||||
name : string,
|
||||
password : string
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const session_key : string = await call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
"/session/begin",
|
||||
{
|
||||
"name": name,
|
||||
"password": password,
|
||||
}
|
||||
);
|
||||
await _data_chest.write("session_key", session_key);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function session_end(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
await call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
"/session/end",
|
||||
null
|
||||
);
|
||||
await _data_chest.delete("session_key");
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function group_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
label : string;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/groups",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/users",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_dav_conf(
|
||||
)
|
||||
: Promise<
|
||||
(
|
||||
null
|
||||
|
|
||||
{
|
||||
address : string;
|
||||
username : string;
|
||||
password : string;
|
||||
setup_hints : Array<
|
||||
{
|
||||
label : string;
|
||||
link : string;
|
||||
remark : (null | string);
|
||||
}
|
||||
>;
|
||||
}
|
||||
)
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/user_dav_conf",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function user_dav_token(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.patch,
|
||||
"/user_dav_token",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_list(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : string;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/calendar",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_get(
|
||||
calendar_id : int
|
||||
)
|
||||
: Promise<
|
||||
{
|
||||
name : string;
|
||||
hue : float;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : string;
|
||||
attributed_group : Array<
|
||||
{
|
||||
group_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
attributed_user : Array<
|
||||
{
|
||||
user_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
};
|
||||
resource_id : int;
|
||||
}
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_add(
|
||||
data : {
|
||||
name : string;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : string;
|
||||
attributed_group : Array<
|
||||
{
|
||||
group_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
attributed_user : Array<
|
||||
{
|
||||
user_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
};
|
||||
resource : (
|
||||
{
|
||||
kind : "local";
|
||||
data : {
|
||||
};
|
||||
}
|
||||
|
|
||||
{
|
||||
kind : "ics_feed";
|
||||
data : {
|
||||
url : string;
|
||||
from_fucked_up_wordpress : boolean;
|
||||
};
|
||||
}
|
||||
);
|
||||
hue : float;
|
||||
}
|
||||
)
|
||||
: Promise<
|
||||
int
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar",
|
||||
{
|
||||
}
|
||||
),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_change(
|
||||
id : int,
|
||||
data : {
|
||||
name : string;
|
||||
hue : float;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : string;
|
||||
attributed_group : Array<
|
||||
{
|
||||
group_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
attributed_user : Array<
|
||||
{
|
||||
user_id : int;
|
||||
level : string;
|
||||
}
|
||||
>;
|
||||
};
|
||||
}
|
||||
)
|
||||
: Promise<
|
||||
void
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{id}}",
|
||||
{
|
||||
"id": id.toFixed(0),
|
||||
}
|
||||
),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_remove(
|
||||
id : int
|
||||
)
|
||||
: Promise<
|
||||
void
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{id}}",
|
||||
{
|
||||
"id": id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_get(
|
||||
calendar_id : int,
|
||||
event_id : int
|
||||
)
|
||||
: Promise<
|
||||
type_event_object
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_add(
|
||||
calendar_id : int,
|
||||
event_data : type_event_object
|
||||
)
|
||||
: Promise<
|
||||
{
|
||||
local_resource_event_id : (null | int);
|
||||
hash : string;
|
||||
}
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.post,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
event_data
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo Möglichkeit den Kalender zu ändern
|
||||
*/
|
||||
export async function calendar_event_change(
|
||||
calendar_id : int,
|
||||
event_id : int,
|
||||
event_object : type_event_object
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.put,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
event_object
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function calendar_event_remove(
|
||||
calendar_id : int,
|
||||
event_id : int
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.delete,
|
||||
lib_plankton.string.coin(
|
||||
"/calendar/{{calendar_id}}/event/{{event_id}}",
|
||||
{
|
||||
"calendar_id": calendar_id.toFixed(0),
|
||||
"event_id": event_id.toFixed(0),
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo prevent loops
|
||||
*/
|
||||
export async function events(
|
||||
from_timestamp : int,
|
||||
to_timestamp : int,
|
||||
{
|
||||
"calendar_ids": calendar_ids = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
calendar_ids ?: (null | Array<int>);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
{
|
||||
hash : string;
|
||||
calendar_id : int;
|
||||
calendar_name : string;
|
||||
hue : float;
|
||||
access_level : string;
|
||||
event_id : (null | int);
|
||||
event_object : type_event_object;
|
||||
}
|
||||
>
|
||||
>
|
||||
{
|
||||
return call(
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/events",
|
||||
Object.assign(
|
||||
{
|
||||
"from": from_timestamp,
|
||||
"to": to_timestamp,
|
||||
},
|
||||
(
|
||||
(calendar_ids === null)
|
||||
?
|
||||
{}
|
||||
:
|
||||
{"calendar_ids": calendar_ids.join(",")}
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
4
source/style/hacks.css
Normal file
4
source/style/hacks.css
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.plankton_input_group_field[rel="resource_kind"]
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -5,56 +5,77 @@
|
|||
|
||||
html
|
||||
{
|
||||
background-color: hsl(var(--hue), 0%, 12.5%);
|
||||
color: hsl(var(--hue), 0%, 100%);
|
||||
background-color: hsl(0, 0%, 12.5%);
|
||||
color: hsl(0, 0%, 100%);
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
header
|
||||
{
|
||||
/*
|
||||
background-color: hsl(0, 0%, 25%);
|
||||
/*
|
||||
border-bottom: 2px solid #888;
|
||||
padding-bottom: 16px;
|
||||
*/
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
a
|
||||
nav > ul
|
||||
{
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav > ul > li
|
||||
{
|
||||
display: inline-block;
|
||||
margin: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
nav a
|
||||
{
|
||||
padding: 8px;
|
||||
text-decoration: none;
|
||||
color: hsl(var(--hue), 0%, 87.5%);
|
||||
}
|
||||
|
||||
a:hover
|
||||
nav a:hover
|
||||
{
|
||||
color: hsl(var(--hue), 0%, 100%);
|
||||
border-bottom: 2px solid hsl(0, 0%, 100%);
|
||||
transition: 1s ease color;
|
||||
}
|
||||
|
||||
button
|
||||
a
|
||||
{
|
||||
padding: 8px 12px;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: hsl(var(--hue), 50%, 50%);
|
||||
}
|
||||
|
||||
background-color: hsl(var(--hue), 0%, 6.125%);
|
||||
border: 1px solid hsl(var(--hue), 0%, 6.125%);
|
||||
color: hsl(0, 0%, 87.5%);
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
a:hover
|
||||
{
|
||||
color: hsl(var(--hue), 50%, 75%);
|
||||
}
|
||||
|
||||
input,select,textarea
|
||||
{
|
||||
background-color: hsl(0, 0%, 25%);
|
||||
border: 1px solid hsl(0, 0%, 25%);
|
||||
color: hsl(0, 0%, 100%);
|
||||
padding: 4px;
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
/*
|
||||
font-family: monospace;
|
||||
*/
|
||||
}
|
||||
|
||||
button
|
||||
{
|
||||
padding: 8px;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input,select,textarea,button
|
||||
{
|
||||
background-color: hsl(0, 0%, 0%);
|
||||
color: hsl(0, 0%, 100%);
|
||||
border: 1px solid hsl(0, 0%, 75%);
|
||||
margin: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
#overlay
|
||||
{
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: hsla(var(--hue), 0%, 0%, 0.75);
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#overlay_content
|
||||
{
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
transform: translate(-50%,-50%);
|
||||
-ms-transform: translate(-50%,-50%);
|
||||
|
||||
padding: 32px;
|
||||
|
||||
background-color: hsl(0, 0%, 12.5%);
|
||||
color: hsl(0, 0%, 100%);
|
||||
}
|
||||
|
||||
#overlay:not(.overlay_active)
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
.widget-caldav-conf-section
|
||||
.caldav-conf-section
|
||||
{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.widget-caldav-conf-section-label
|
||||
.caldav-conf-section-label
|
||||
{
|
||||
margin-left: 16px;
|
||||
display: block;
|
||||
|
|
@ -11,12 +11,12 @@
|
|||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.widget-caldav-conf-section-value
|
||||
.caldav-conf-section-value
|
||||
{
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
.widget-caldav-conf-section-value-regular
|
||||
.caldav-conf-section-value-regular
|
||||
{
|
||||
font-family: monospace;
|
||||
}
|
||||
13
source/style/page-calendar_add.css
Normal file
13
source/style/page-calendar_add.css
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#calendar_add .plankton_input_group_field[rel="attributed"] > .plankton_input_list > .plankton_input_list_elements > .plankton_input_list_element
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#calendar_add .plankton_input_group_field[rel="attributed"] > .plankton_input_list > .plankton_input_list_elements > .plankton_input_list_element > .plankton_input_list_element_input > .plankton_input_group
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
8
source/style/page-event_add.css
Normal file
8
source/style/page-event_add.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#event_add .plankton_input_group_field[rel="begin"] > .plankton_input_group
|
||||
,
|
||||
#event_add .plankton_input_group_field[rel="end"] > .plankton_input_soft_container > .plankton_input_soft_core_wrapper > .plankton_input_group
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
8
source/style/page-event_edit.css
Normal file
8
source/style/page-event_edit.css
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#event_edit .plankton_input_group_field[rel="begin"] > .plankton_input_group
|
||||
,
|
||||
#event_edit .plankton_input_group_field[rel="end"] > .plankton_input_soft_container > .plankton_input_soft_core_wrapper > .plankton_input_group
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
63
source/style/page-overview.css
Normal file
63
source/style/page-overview.css
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#overview-head
|
||||
{
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#overview-body
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#overview-body #overview-pane-left
|
||||
{
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
#overview-body #overview-pane-right
|
||||
{
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
@media all and (max-width: 950px)
|
||||
{
|
||||
#overview #overview-pane-left
|
||||
{
|
||||
flex-basis: 0%;
|
||||
}
|
||||
|
||||
#overview #overview-pane-left > *
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#overview #overview-pane-right
|
||||
{
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#overview #overview-pane-right-listview {}
|
||||
#overview #overview-pane-right-weekview {display: none;}
|
||||
}
|
||||
|
||||
@media not all and (max-width: 950px)
|
||||
{
|
||||
#overview #overview-pane-left
|
||||
{
|
||||
flex-basis: 12.5%;
|
||||
}
|
||||
|
||||
#overview #overview-pane-right
|
||||
{
|
||||
flex-basis: 87.5%;
|
||||
}
|
||||
|
||||
#overview #overview-pane-right-listview {display: none;}
|
||||
#overview #overview-pane-right-weekview {}
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +1,26 @@
|
|||
.plankton_input_group_field
|
||||
{
|
||||
.plankton_input_group_field {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.plankton_input_group_field_label
|
||||
{
|
||||
.plankton_input_group_field_label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 0.8em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.plankton_input_soft_container > *
|
||||
{
|
||||
.plankton_input_soft_container > * {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.plankton_input_soft_setter
|
||||
{
|
||||
.plankton_input_soft_setter {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.plankton_input_soft_inactive
|
||||
{
|
||||
.plankton_input_soft_inactive {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.plankton_input_group
|
||||
{
|
||||
.plankton_input_group {
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +44,3 @@
|
|||
{
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.plankton_input_password_exhibit
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
.listview-add
|
||||
{
|
||||
margin-left: 12px;
|
||||
/*
|
||||
text-transform: capitalize;
|
||||
*/
|
||||
}
|
||||
|
||||
.listview-add-hidden
|
||||
|
|
@ -24,11 +26,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.listview-entry-hidden
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.listview-entry-name
|
||||
{
|
||||
font-weight: bold;
|
||||
52
source/style/widget-sources.css
Normal file
52
source/style/widget-sources.css
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
.sources
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.sources-entry
|
||||
{
|
||||
margin: 8px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.sources-entry-head
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sources-entry-body
|
||||
{
|
||||
display: block;
|
||||
transition: max-height ease 0.5s;
|
||||
}
|
||||
|
||||
.sources-entry-body > ul
|
||||
{
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin-left: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.sources-entry-body > ul > li
|
||||
{
|
||||
/*
|
||||
display: block;
|
||||
*/
|
||||
margin-top: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sources-entry:not(.sources-entry-open) > .sources-entry-head {}
|
||||
.sources-entry:not(.sources-entry-open) > .sources-entry-body {max-height: 0; overflow: hidden;}
|
||||
|
||||
.sources-entry.sources-entry-open > .sources-entry-head {}
|
||||
.sources-entry.sources-entry-open > .sources-entry-body {max-height: 240px; overflow: auto;}
|
||||
|
||||
.sources-entry-hidden
|
||||
{
|
||||
filter: saturate(0);
|
||||
}
|
||||
|
|
@ -1,32 +1,12 @@
|
|||
.weekview-controls
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: right;
|
||||
|
||||
margin-bottom: 12px;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.weekview-controls > *
|
||||
.weekview-control
|
||||
{
|
||||
flex-basis: 0;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
|
||||
margin: 0 0 0 16px;
|
||||
}
|
||||
|
||||
.weekview-control-label
|
||||
{
|
||||
display: block;
|
||||
|
||||
font-size: 0.75em;
|
||||
/*
|
||||
text-transform: uppercase;
|
||||
*/
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.weekview-table table
|
||||
|
|
@ -44,21 +24,18 @@
|
|||
|
||||
.weekview-cell-day
|
||||
{
|
||||
/* todo */
|
||||
width: 13.5%;
|
||||
}
|
||||
|
||||
.weekview-cell-week
|
||||
{
|
||||
/* todo */
|
||||
width: 5.5%;
|
||||
}
|
||||
|
||||
.weekview-cell-regular
|
||||
{
|
||||
/* todo */
|
||||
width: 13.5%;
|
||||
height: 100px;
|
||||
height: 120px;
|
||||
|
||||
cursor: copy;
|
||||
}
|
||||
|
|
@ -76,12 +53,12 @@
|
|||
.weekview-day
|
||||
{
|
||||
font-size: 0.75em;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.weekview-events
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin: 0; padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
334
source/types.ts
334
source/types.ts
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
namespace _dali
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_access_level
|
||||
{
|
||||
none,
|
||||
view,
|
||||
edit,
|
||||
admin
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_group_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_group_object = {
|
||||
name : string;
|
||||
label : string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_user_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_user_object = {
|
||||
name : string;
|
||||
label : string;
|
||||
email_address : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @todo deprecate?
|
||||
*/
|
||||
export type type_local_resource_event_id = int;
|
||||
|
||||
|
||||
/**
|
||||
* info: das ist nicht deckungsgleich mit der Event-ID aus dem Backend; hiermit werden sowohl lokale als auch
|
||||
* extern eingebundene Events kodiert
|
||||
*
|
||||
* @example "local:1234"
|
||||
* @example "ics~2345"
|
||||
*/
|
||||
export type type_event_key = string;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_event_object = {
|
||||
name : string;
|
||||
begin : lib_plankton.pit.type_datetime;
|
||||
end : (
|
||||
null
|
||||
|
|
||||
lib_plankton.pit.type_datetime
|
||||
);
|
||||
location : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
link : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
description : (
|
||||
null
|
||||
|
|
||||
string
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_event_entry = {
|
||||
id : (null | type_local_resource_event_id);
|
||||
key : type_event_key;
|
||||
object : type_event_object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_event_object_extended = {
|
||||
key : type_event_key;
|
||||
calendar_id : type_calendar_id;
|
||||
calendar_name : string;
|
||||
hue : float;
|
||||
access_level : enum_access_level;
|
||||
event_id : (null | type_local_resource_event_id);
|
||||
event_object : type_event_object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_resource_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_resource_object = (
|
||||
{
|
||||
kind : "local";
|
||||
data : {
|
||||
events : Array<
|
||||
type_event_object
|
||||
>;
|
||||
};
|
||||
}
|
||||
|
|
||||
{
|
||||
kind : "caldav";
|
||||
data : {
|
||||
read_only : boolean;
|
||||
url : string;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_calendar_id = int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_calendar_object = {
|
||||
name : string;
|
||||
hue : float;
|
||||
access : {
|
||||
public : boolean;
|
||||
default_level : enum_access_level;
|
||||
attributed_group : lib_plankton.map.type_map<
|
||||
type_group_id,
|
||||
enum_access_level
|
||||
>;
|
||||
attributed_user : lib_plankton.map.type_map<
|
||||
type_user_id,
|
||||
enum_access_level
|
||||
>;
|
||||
};
|
||||
resource_id : type_resource_id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_calendar_object_reduced = {
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : enum_access_level;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_calendar_object_reduced_with_id = {
|
||||
id : type_calendar_id;
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : enum_access_level;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function access_level_encode(
|
||||
access_level : _dali.enum_access_level
|
||||
)
|
||||
: ("none" | "view" | "edit" | "admin")
|
||||
{
|
||||
switch (access_level)
|
||||
{
|
||||
case _dali.enum_access_level.none: return "none";
|
||||
case _dali.enum_access_level.view: return "view";
|
||||
case _dali.enum_access_level.edit: return "edit";
|
||||
case _dali.enum_access_level.admin: return "admin";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function access_level_decode(
|
||||
representation : /*("none" | "view" | "edit" | "admin")*/string
|
||||
)
|
||||
: _dali.enum_access_level
|
||||
{
|
||||
switch (representation)
|
||||
{
|
||||
case "none": return _dali.enum_access_level.none;
|
||||
case "view": return _dali.enum_access_level.view;
|
||||
case "edit": return _dali.enum_access_level.edit;
|
||||
case "admin": return _dali.enum_access_level.admin;
|
||||
default: throw (new Error("invalid access level representation: " + representation));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_view_mode
|
||||
{
|
||||
week,
|
||||
list,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_mode_encode(
|
||||
mode : _dali.enum_view_mode
|
||||
)
|
||||
: string
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case _dali.enum_view_mode.week: {return "week"; break;}
|
||||
case _dali.enum_view_mode.list: {return "list"; break;}
|
||||
default: {throw (new Error("invalid mode"));}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_mode_decode(
|
||||
view_mode_encoded : string
|
||||
)
|
||||
: _dali.enum_view_mode
|
||||
{
|
||||
const map : Record<string, _dali.enum_view_mode> = {
|
||||
"week": _dali.enum_view_mode.week,
|
||||
"list": _dali.enum_view_mode.list,
|
||||
};
|
||||
if (! (view_mode_encoded in map))
|
||||
{
|
||||
throw (new Error("invalid mode: " + view_mode_encoded));
|
||||
}
|
||||
else
|
||||
{
|
||||
return map[view_mode_encoded];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_view_kind
|
||||
{
|
||||
regular,
|
||||
touch,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_kind_encode(
|
||||
kind : _dali.enum_view_kind
|
||||
)
|
||||
: string
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case _dali.enum_view_kind.regular: {return "regular"; break;}
|
||||
case _dali.enum_view_kind.touch: {return "touch"; break;}
|
||||
default: {throw (new Error("invalid kind"));}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function view_kind_decode(
|
||||
view_kind_encoded : string
|
||||
)
|
||||
: _dali.enum_view_kind
|
||||
{
|
||||
const map : Record<string, _dali.enum_view_kind> = {
|
||||
"regular": _dali.enum_view_kind.regular,
|
||||
"touch": _dali.enum_view_kind.touch,
|
||||
};
|
||||
if (! (view_kind_encoded in map))
|
||||
{
|
||||
throw (new Error("invalid kind: " + view_kind_encoded));
|
||||
}
|
||||
else
|
||||
{
|
||||
return map[view_kind_encoded];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_caldav
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
target_element.innerHTML = "";
|
||||
const conf = await _dali.backend.user_dav_conf();
|
||||
target_element.innerHTML = await _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"main",
|
||||
{
|
||||
"title": lib_plankton.translate.get("widget.caldav.title"),
|
||||
"content": (
|
||||
(conf === null)
|
||||
?
|
||||
await _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"unavailable",
|
||||
{
|
||||
"text": lib_plankton.translate.get("widget.caldav.unavailable"),
|
||||
}
|
||||
)
|
||||
:
|
||||
await _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"available",
|
||||
{
|
||||
"conf_title": lib_plankton.translate.get("widget.caldav.conf.title"),
|
||||
"conf_content": (
|
||||
(conf.password === null)
|
||||
?
|
||||
await _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"conf-token_unset",
|
||||
{
|
||||
"text": lib_plankton.translate.get("widget.caldav.conf.token_unset")
|
||||
}
|
||||
)
|
||||
:
|
||||
await _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"conf-token_set",
|
||||
{
|
||||
"address_label": lib_plankton.translate.get("widget.caldav.conf.address"),
|
||||
"address_value": conf.address,
|
||||
"username_label": lib_plankton.translate.get("widget.caldav.conf.username"),
|
||||
"username_value": conf.username,
|
||||
"password_label": lib_plankton.translate.get("widget.caldav.conf.password"),
|
||||
"password_value": conf.password,
|
||||
"setup_hints_label": lib_plankton.translate.get("widget.caldav.conf.setup_hints"),
|
||||
"setup_hint_entries": (
|
||||
await lib_plankton.call.promise_condense<string, unknown>(
|
||||
conf.setup_hints
|
||||
.map(
|
||||
entry => () => _dali.helpers.template_coin(
|
||||
"widget-caldav",
|
||||
"conf-setup_hint_entry",
|
||||
{
|
||||
"text": entry.label,
|
||||
"href": entry.link,
|
||||
"remark": (
|
||||
(entry.remark === null)
|
||||
?
|
||||
""
|
||||
:
|
||||
lib_plankton.string.coin(
|
||||
" — {{content}}",
|
||||
{
|
||||
"content": entry.remark,
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
).join("")
|
||||
}
|
||||
)
|
||||
),
|
||||
"set_token_title": lib_plankton.translate.get("widget.caldav.set_token.title"),
|
||||
"set_token_action": (
|
||||
(conf.password === null)
|
||||
?
|
||||
lib_plankton.translate.get("widget.caldav.set_token.action.set")
|
||||
:
|
||||
lib_plankton.translate.get("widget.caldav.set_token.action.overwrite")
|
||||
),
|
||||
}
|
||||
)
|
||||
),
|
||||
"close": lib_plankton.translate.get("common.close"),
|
||||
}
|
||||
);
|
||||
// logic
|
||||
{
|
||||
// set token
|
||||
{
|
||||
if (conf === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
target_element.querySelector(".widget-caldav-set_token > button").addEventListener(
|
||||
"click",
|
||||
async () => {
|
||||
await _dali.backend.user_dav_token();
|
||||
await this.load(target_element);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// close
|
||||
{
|
||||
target_element.querySelector(".widget-caldav-close").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
// init
|
||||
{
|
||||
(target_element.querySelector(".widget-caldav-close") as HTMLElement).focus();
|
||||
}
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<div class="widget-caldav-conf-section" class="widget-caldav-conf-address">
|
||||
<span class="widget-caldav-conf-section-label">{{address_label}}</span>
|
||||
<span class="widget-caldav-conf-section-value widget-caldav-conf-section-value-regular">{{address_value}}</span>
|
||||
</div>
|
||||
<div class="widget-caldav-conf-section" class="widget-caldav-conf-username">
|
||||
<span class="widget-caldav-conf-section-label">{{username_label}}</span>
|
||||
<span class="widget-caldav-conf-section-value widget-caldav-conf-section-value-regular">{{username_value}}</span>
|
||||
</div>
|
||||
<div class="widget-caldav-conf-section" class="widget-caldav-conf-password">
|
||||
<span class="widget-caldav-conf-section-label">{{password_label}}</span>
|
||||
<span class="widget-caldav-conf-section-value widget-caldav-conf-section-value-regular">{{password_value}}</span>
|
||||
</div>
|
||||
<div class="widget-caldav-conf-section" class="widget-caldav-conf-setup_hints">
|
||||
<span class="widget-caldav-conf-section-label">{{setup_hints_label}}</span>
|
||||
<ul>
|
||||
{{setup_hint_entries}}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
<div class="widget-caldav-conf-info">
|
||||
({{text}})
|
||||
</div>
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<div class="widget-caldav">
|
||||
<h2>{{title}}</h2>
|
||||
<div class="widget-caldav-content">
|
||||
{{content}}
|
||||
</div>
|
||||
<hr/>
|
||||
<button class="widget-caldav-close">{{close}}</button>
|
||||
</div>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<div class="widget-caldav-info">
|
||||
{{text}}
|
||||
</div>
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_calendar_edit
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private groups : Array<{id : _dali.type_group_id; object : _dali.type_group_object;}>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private users : Array<{id : _dali.type_user_id; name : string;}>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private read_only : boolean;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_cancel ?: (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_add ?: (null | ((value : _dali.type_calendar_object) => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_change ?: (null | ((value : _dali.type_calendar_object) => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_remove ?: (null | ((value : _dali.type_calendar_object) => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private initial_value : _dali.type_calendar_object;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
groups : Array<{id : _dali.type_group_id; object : _dali.type_group_object;}>,
|
||||
users : Array<{id : _dali.type_user_id; name : string;}>,
|
||||
initial_value : _dali.type_calendar_object,
|
||||
{
|
||||
"read_only": read_only = false,
|
||||
"action_cancel": action_cancel = null,
|
||||
"action_add": action_add = null,
|
||||
"action_change": action_change = null,
|
||||
"action_remove": action_remove = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
read_only ?: boolean;
|
||||
action_cancel ?: (null | (() => void));
|
||||
action_add ?: (null | ((value : _dali.type_calendar_object) => void))
|
||||
action_change ?: (null | ((value : _dali.type_calendar_object) => void));
|
||||
action_remove ?: (null | ((value : _dali.type_calendar_object) => void));
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.groups = groups;
|
||||
this.users = users;
|
||||
this.initial_value = initial_value;
|
||||
this.read_only = read_only;
|
||||
this.action_cancel = action_cancel;
|
||||
this.action_add = action_add;
|
||||
this.action_change = action_change;
|
||||
this.action_remove = action_remove;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
) : Promise<void>
|
||||
{
|
||||
const dom_root = await _dali.helpers.element_from_template(
|
||||
"widget-calendar_edit",
|
||||
"main",
|
||||
{
|
||||
}
|
||||
);
|
||||
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
_dali.type_calendar_object,
|
||||
_dali.type_calendar_object
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
_dali.type_calendar_object,
|
||||
_dali.type_calendar_object
|
||||
>(
|
||||
(value) => value,
|
||||
(raw) => raw,
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(),
|
||||
"label": lib_plankton.translate.get("calendar.name")
|
||||
},
|
||||
{
|
||||
"name": "hue",
|
||||
"input": new lib_plankton.zoo_input.class_input_hue(
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.hue"),
|
||||
},
|
||||
{
|
||||
"name": "access",
|
||||
"input": new lib_plankton.zoo_input.class_input_group(
|
||||
[
|
||||
{
|
||||
"name": "public",
|
||||
"input": new lib_plankton.zoo_input.class_input_checkbox(),
|
||||
"label": lib_plankton.translate.get("calendar.access.public"),
|
||||
},
|
||||
{
|
||||
"name": "default_level",
|
||||
"input": _dali.helpers.input_access_level(),
|
||||
"label": lib_plankton.translate.get("calendar.access.default_level"),
|
||||
},
|
||||
{
|
||||
"name": "attributed_group",
|
||||
"input": _dali.helpers.input_attributed_access_group(this.groups),
|
||||
"label": lib_plankton.translate.get("calendar.access.attributed_group"),
|
||||
},
|
||||
{
|
||||
"name": "attributed_user",
|
||||
"input": _dali.helpers.input_attributed_access_user(this.users),
|
||||
"label": lib_plankton.translate.get("calendar.access.attributed_user"),
|
||||
},
|
||||
]
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.access.access"),
|
||||
},
|
||||
{
|
||||
"name": "resource",
|
||||
"input": new lib_plankton.zoo_input.class_input_hidden(
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.resource"),
|
||||
},
|
||||
]
|
||||
),
|
||||
(
|
||||
[]
|
||||
// add
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_add === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.calendar_edit.actions.add"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : _dali.type_calendar_object = await get_value();
|
||||
this.action_add(value);
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// change
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_change === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.calendar_edit.actions.change"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : _dali.type_calendar_object = await get_value();
|
||||
this.action_change(value);
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// remove
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_remove === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.calendar_edit.actions.remove"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
if (! window.confirm(lib_plankton.translate.get("common.confirm_deletion")))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const value : _dali.type_calendar_object = await get_value();
|
||||
this.action_remove(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// cancel
|
||||
.concat(
|
||||
(! (this.action_cancel === null))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("common.cancel"),
|
||||
"procedure": async () => {
|
||||
this.action_cancel();
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
)
|
||||
);
|
||||
await form.setup(dom_root);
|
||||
await form.input_lock(this.read_only);
|
||||
await form.input_write(this.initial_value);
|
||||
|
||||
target_element.appendChild(dom_root);
|
||||
form.input_focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
.widget-calendar_edit .plankton_input_group_field[rel="resource"]
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<div class="widget-calendar_edit">
|
||||
</div>
|
||||
|
|
@ -1,336 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_value = {
|
||||
calendar_id : (null | _dali.type_calendar_id);
|
||||
event_name : string;
|
||||
event_begin : lib_plankton.pit.type_datetime;
|
||||
event_end : (null | lib_plankton.pit.type_datetime);
|
||||
event_location : (null | string);
|
||||
event_link : (null | string);
|
||||
event_description : (null | string);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_representation = {
|
||||
calendar_id : string;
|
||||
event_name : string;
|
||||
event_begin : lib_plankton.pit.type_datetime;
|
||||
event_end : (null | lib_plankton.pit.type_datetime);
|
||||
event_location : (null | string);
|
||||
event_link : (null | string);
|
||||
event_description : (null | string);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_event_edit
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
* [data]
|
||||
*/
|
||||
private available_calendars : Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : _dali.enum_access_level;
|
||||
}
|
||||
>;
|
||||
|
||||
|
||||
/**
|
||||
* [data]
|
||||
*/
|
||||
private read_only : boolean;
|
||||
|
||||
|
||||
/**
|
||||
* [data]
|
||||
*/
|
||||
private initial_value : type_value;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_cancel ?: (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_add ?: (null | ((value : type_value) => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_change ?: (null | ((value : type_value) => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_remove ?: (null | ((value : type_value) => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
available_calendars : Array<
|
||||
{
|
||||
id : int;
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : _dali.enum_access_level;
|
||||
}
|
||||
>,
|
||||
initial_value : type_value,
|
||||
{
|
||||
"read_only": read_only = false,
|
||||
"action_cancel": action_cancel = null,
|
||||
"action_add": action_add = null,
|
||||
"action_change": action_change = null,
|
||||
"action_remove": action_remove = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
read_only ?: boolean;
|
||||
action_cancel ?: (null | (() => void));
|
||||
action_add ?: (null | ((value : type_value) => void));
|
||||
action_change ?: (null | ((value : type_value) => void));
|
||||
action_remove ?: (null | ((value : type_value) => void));
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
// data
|
||||
this.read_only = read_only;
|
||||
this.available_calendars = available_calendars;
|
||||
this.initial_value = initial_value;
|
||||
|
||||
// hooks
|
||||
this.action_cancel = action_cancel;
|
||||
this.action_add = action_add;
|
||||
this.action_change = action_change;
|
||||
this.action_remove = action_remove;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
) : Promise<void>
|
||||
{
|
||||
const dom_root = await _dali.helpers.element_from_template(
|
||||
"widget-event_edit",
|
||||
"main",
|
||||
{
|
||||
}
|
||||
);
|
||||
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
type_value,
|
||||
type_representation
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
type_value,
|
||||
type_representation
|
||||
>(
|
||||
(value) => ({
|
||||
"calendar_id": (value.calendar_id ?? this.available_calendars[0].id).toFixed(0),
|
||||
"event_name": value.event_name,
|
||||
"event_begin": value.event_begin,
|
||||
"event_end": value.event_end,
|
||||
"event_location": value.event_location,
|
||||
"event_link": value.event_link,
|
||||
"event_description": value.event_description,
|
||||
}),
|
||||
(representation) => ({
|
||||
"calendar_id": parseInt(representation.calendar_id),
|
||||
"event_name": representation.event_name,
|
||||
"event_begin": representation.event_begin,
|
||||
"event_end": representation.event_end,
|
||||
"event_location": representation.event_location,
|
||||
"event_link": representation.event_link,
|
||||
"event_description": representation.event_description,
|
||||
}),
|
||||
new lib_plankton.zoo_input.class_input_group<any>(
|
||||
[
|
||||
{
|
||||
"name": "calendar_id",
|
||||
"input": new lib_plankton.zoo_input.class_input_selection(
|
||||
(
|
||||
this.available_calendars
|
||||
.map(
|
||||
(entry) => ({
|
||||
"value": entry.id.toFixed(0),
|
||||
"label": entry.name,
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("calendar.calendar")
|
||||
},
|
||||
{
|
||||
"name": "event_name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.name")
|
||||
},
|
||||
{
|
||||
"name": "event_begin",
|
||||
"input": _dali.helpers.datetime_input(
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.begin")
|
||||
},
|
||||
{
|
||||
"name": "event_end",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
|
||||
_dali.helpers.datetime_input(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.end")
|
||||
},
|
||||
{
|
||||
"name": "event_location",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.location")
|
||||
},
|
||||
{
|
||||
"name": "event_link",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_text(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.link")
|
||||
},
|
||||
{
|
||||
"name": "event_description",
|
||||
"input": new lib_plankton.zoo_input.class_input_soft<string>(
|
||||
new lib_plankton.zoo_input.class_input_textarea(
|
||||
)
|
||||
),
|
||||
"label": lib_plankton.translate.get("event.description")
|
||||
},
|
||||
]
|
||||
),
|
||||
(
|
||||
[]
|
||||
// add
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_add === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.event_edit.actions.add"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : type_value = await get_value();
|
||||
this.action_add(value);
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// change
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_change === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.event_edit.actions.change"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : type_value = await get_value();
|
||||
this.action_change(value);
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// remove
|
||||
.concat(
|
||||
((! this.read_only) && (! (this.action_remove === null)))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.event_edit.actions.remove"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
if (! window.confirm(lib_plankton.translate.get("common.confirm_deletion")))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const value : type_value = await get_value();
|
||||
this.action_remove(value);
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
// cancel
|
||||
.concat(
|
||||
(! (this.action_cancel === null))
|
||||
?
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("common.cancel"),
|
||||
"procedure": async () => {
|
||||
this.action_cancel();
|
||||
}
|
||||
},
|
||||
]
|
||||
:
|
||||
[]
|
||||
)
|
||||
)
|
||||
);
|
||||
await form.setup(dom_root);
|
||||
await form.input_lock(this.read_only);
|
||||
await form.input_write(this.initial_value);
|
||||
|
||||
target_element.appendChild(dom_root);
|
||||
form.input_focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<div class="widget-event_edit">
|
||||
</div>
|
||||
|
|
@ -1,56 +1,47 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
namespace _zeitbild.frontend_web.widgets.listview
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_entry = {
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id;
|
||||
calendar_name : string;
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id);
|
||||
event_object : _zeitbild.frontend_web.type.event_object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_get_entries = (
|
||||
(
|
||||
from_pit : lib_plankton.pit.type_pit,
|
||||
to_pit : lib_plankton.pit.type_pit,
|
||||
calendar_ids : Array<_dali.type_calendar_id>
|
||||
calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id>
|
||||
)
|
||||
=>
|
||||
Promise<Array<_dali.type_event_object_extended>>
|
||||
Promise<Array<type_entry>>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_listview implements lib_plankton.zoo_widget.interface_widget
|
||||
export class class_widget_listview extends _zeitbild.class_widget
|
||||
{
|
||||
|
||||
/**
|
||||
* [dependency]
|
||||
*/
|
||||
private get_entries : type_get_entries;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_select : (
|
||||
private action_select_event : (
|
||||
(
|
||||
event_key : _dali.type_event_key
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level,
|
||||
event_id : _zeitbild.frontend_web.type.local_resource_event_id
|
||||
)
|
||||
=>
|
||||
void
|
||||
|
|
@ -58,7 +49,6 @@ namespace _dali.widgets
|
|||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_add : (
|
||||
(
|
||||
|
|
@ -68,32 +58,16 @@ namespace _dali.widgets
|
|||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private include_passed : boolean;
|
||||
|
||||
|
||||
/**
|
||||
* [state]
|
||||
*/
|
||||
private container : (null | Element);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
get_entries : type_get_entries,
|
||||
{
|
||||
"include_passed": include_passed = false,
|
||||
"action_select": action_select = ((event_key) => {}),
|
||||
"action_add": action_add = (() => {}),
|
||||
}
|
||||
:
|
||||
{
|
||||
include_passed ?: boolean;
|
||||
action_select ?: (
|
||||
options : {
|
||||
action_select_event ?: (
|
||||
(
|
||||
event_key : _dali.type_event_key
|
||||
calendar_id : _zeitbild.frontend_web.type.calendar_id,
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level,
|
||||
event_id : _zeitbild.frontend_web.type.local_resource_event_id
|
||||
)
|
||||
=>
|
||||
void
|
||||
|
|
@ -104,75 +78,34 @@ namespace _dali.widgets
|
|||
=>
|
||||
void
|
||||
);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
} = {}
|
||||
)
|
||||
{
|
||||
// dependencies
|
||||
options = Object.assign(
|
||||
{
|
||||
"action_select_event": (calendar_id, access_level, event_id) => {},
|
||||
"action_select_add": () => {},
|
||||
},
|
||||
options
|
||||
);
|
||||
super();
|
||||
this.get_entries = get_entries;
|
||||
|
||||
// hooks
|
||||
this.action_select = action_select;
|
||||
this.action_add = action_add;
|
||||
|
||||
// state
|
||||
this.include_passed = include_passed;
|
||||
this.container = null;
|
||||
this.action_select_event = options.action_select_event;
|
||||
this.action_add = options.action_add;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public toggle_visibility(
|
||||
calendar_id : _dali.type_calendar_id,
|
||||
{
|
||||
"mode": mode = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
mode ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.container.querySelectorAll(".listview-entry").forEach(
|
||||
(element) => {
|
||||
const rel : string = element.getAttribute("rel");
|
||||
const parts : Array<string> = rel.split("/");
|
||||
const calendar_id_ : _dali.type_calendar_id = parseInt(parts[0]);
|
||||
if (! (calendar_id === calendar_id_))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
element.classList.toggle(
|
||||
"listview-entry-hidden",
|
||||
((mode !== null) ? (! mode) : undefined)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public async update_entries(
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
// structure
|
||||
public async load(
|
||||
target_element : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now();
|
||||
const from_pit : lib_plankton.pit.type_pit = now_pit;
|
||||
const to_pit : lib_plankton.pit.type_pit = lib_plankton.pit.shift_week(now_pit, +4);
|
||||
const entries : Array<_dali.type_event_object_extended> = await this.get_entries(
|
||||
const entries : Array<type_entry> = await this.get_entries(
|
||||
from_pit,
|
||||
to_pit,
|
||||
null
|
||||
|
|
@ -184,25 +117,28 @@ namespace _dali.widgets
|
|||
lib_plankton.pit.from_datetime(y.event_object.begin)
|
||||
)
|
||||
);
|
||||
const dom_list : HTMLElement = this.container.querySelector(".listview-entries");
|
||||
dom_list.innerHTML = (
|
||||
(
|
||||
await _dali.helpers.promise_row<string>(
|
||||
entries
|
||||
.filter(
|
||||
(entry) => (
|
||||
this.include_passed
|
||||
|
||||
// view
|
||||
{
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"widget-listview",
|
||||
"main",
|
||||
{
|
||||
"add_href": "",
|
||||
"add_label": lib_plankton.translate.get("widget.listview.add"),
|
||||
"add_extra_classes": (
|
||||
(! await _zeitbild.frontend_web.backend.is_logged_in())
|
||||
?
|
||||
true
|
||||
" listview-add-hidden"
|
||||
:
|
||||
lib_plankton.pit.is_after(
|
||||
lib_plankton.pit.from_datetime(entry.event_object.begin),
|
||||
now_pit
|
||||
)
|
||||
)
|
||||
)
|
||||
""
|
||||
),
|
||||
"entries": (
|
||||
(
|
||||
await _zeitbild.frontend_web.helpers.promise_row<string>(
|
||||
entries
|
||||
.map(
|
||||
(entry) => () => _dali.helpers.template_coin(
|
||||
(entry) => () => _zeitbild.frontend_web.helpers.template_coin(
|
||||
"widget-listview",
|
||||
"entry",
|
||||
{
|
||||
|
|
@ -264,66 +200,43 @@ namespace _dali.widgets
|
|||
entry.event_object.description
|
||||
),
|
||||
"raw": JSON.stringify(entry),
|
||||
"color": _dali.helpers.event_color(entry.hue),
|
||||
"rel": entry.key,
|
||||
"color": lib_plankton.color.output_hex(
|
||||
lib_plankton.color.give_generic(
|
||||
(entry.calendar_id - 1),
|
||||
{
|
||||
"saturation": 0.375,
|
||||
"value": 0.375,
|
||||
}
|
||||
),
|
||||
),
|
||||
"rel": lib_plankton.string.coin(
|
||||
"{{calendar_id}}/{{event_id}}/{{access_level}}",
|
||||
{
|
||||
"calendar_id": entry.calendar_id.toFixed(0),
|
||||
"event_id": (
|
||||
(! (entry.event_id === null))
|
||||
?
|
||||
entry.event_id.toFixed(0)
|
||||
:
|
||||
"-"
|
||||
),
|
||||
"access_level": (() => {
|
||||
switch (entry.access_level) {
|
||||
case _zeitbild.frontend_web.type.enum_access_level.none: return "none";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.view: return "view";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit";
|
||||
case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin";
|
||||
}
|
||||
}) (),
|
||||
}
|
||||
),
|
||||
},
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.join("")
|
||||
);
|
||||
}
|
||||
// listeners
|
||||
{
|
||||
this.container.querySelectorAll(".listview-entry").forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
if ((event.target as Element).nodeName === "A")
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const event_key : string = element.getAttribute("rel");
|
||||
this.action_select(event_key);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
this.container = target_element;
|
||||
|
||||
// view
|
||||
{
|
||||
target_element.innerHTML = await _dali.helpers.template_coin(
|
||||
"widget-listview",
|
||||
"main",
|
||||
{
|
||||
"add_href": "",
|
||||
"add_label": lib_plankton.translate.get("widget.listview.add"),
|
||||
"add_extra_classes": (
|
||||
(! await _dali.is_logged_in())
|
||||
?
|
||||
" listview-add-hidden"
|
||||
:
|
||||
""
|
||||
),
|
||||
"entries": "",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -337,9 +250,44 @@ namespace _dali.widgets
|
|||
this.action_add();
|
||||
}
|
||||
);
|
||||
target_element.querySelectorAll(".listview-entry").forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
if ((event.target as Element).nodeName === "A") {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
const rel : string = element.getAttribute("rel");
|
||||
const parts : Array<string> = rel.split("/");
|
||||
const calendar_id : _zeitbild.frontend_web.type.calendar_id = parseInt(parts[0]);
|
||||
const event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id) = (
|
||||
parts[1] === "-"
|
||||
?
|
||||
null
|
||||
:
|
||||
parseInt(parts[1])
|
||||
);
|
||||
const access_level : _zeitbild.frontend_web.type.enum_access_level = (() => {
|
||||
switch (parts[2]) {
|
||||
case "none": return _zeitbild.frontend_web.type.enum_access_level.none;
|
||||
case "view": return _zeitbild.frontend_web.type.enum_access_level.view;
|
||||
case "edit": return _zeitbild.frontend_web.type.enum_access_level.edit;
|
||||
case "admin": return _zeitbild.frontend_web.type.enum_access_level.admin;
|
||||
}
|
||||
}) ();
|
||||
this.action_select_event(
|
||||
calendar_id,
|
||||
access_level,
|
||||
event_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
await this.update_entries();
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_login implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
* [data]
|
||||
*/
|
||||
private initial_name : string;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_cancel : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_success : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"initial_name": initial_name = "",
|
||||
"action_cancel": action_cancel = null,
|
||||
"action_success": action_success = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
initial_name ?: string;
|
||||
action_cancel ?: (null | (() => void));
|
||||
action_success ?: (null | (() => void));
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.initial_name = initial_name;
|
||||
this.action_cancel = action_cancel;
|
||||
this.action_success = action_success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const preparation : {kind : string; data : any;} = await _dali.backend.session_prepare(
|
||||
{
|
||||
"oidc_redirect_uri_template": _dali.conf.get()["misc"]["oidc_redirect_uri_template"],
|
||||
}
|
||||
);
|
||||
switch (preparation.kind)
|
||||
{
|
||||
case "internal":
|
||||
{
|
||||
const sub_widget : lib_plankton.zoo_widget.interface_widget = (
|
||||
new class_widget_login_internal(
|
||||
preparation.data,
|
||||
{
|
||||
"initial_name": this.initial_name,
|
||||
"action_cancel": this.action_cancel,
|
||||
"action_success": this.action_success,
|
||||
}
|
||||
)
|
||||
);
|
||||
await sub_widget.load(target_element);
|
||||
break;
|
||||
}
|
||||
case "oidc":
|
||||
{
|
||||
const sub_widget : lib_plankton.zoo_widget.interface_widget = (
|
||||
new class_widget_login_oidc(
|
||||
preparation.data,
|
||||
{
|
||||
"action_cancel": this.action_cancel,
|
||||
"action_success": this.action_success,
|
||||
}
|
||||
)
|
||||
);
|
||||
await sub_widget.load(target_element);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw (new Error("unhandled login kind: " + preparation.kind));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_login_internal
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private preparation_data : any;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private initial_name : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_cancel : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_success : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
preparation_data : any,
|
||||
{
|
||||
"initial_name": initial_name = null,
|
||||
"action_cancel": action_cancel = null,
|
||||
"action_success": action_success = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
initial_name ?: (null | string);
|
||||
action_cancel ?: (null | (() => void));
|
||||
action_success ?: (null | (() => void));
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.preparation_data = preparation_data;
|
||||
this.initial_name = initial_name;
|
||||
this.action_cancel = action_cancel;
|
||||
this.action_success = action_success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const form : lib_plankton.zoo_form.class_form<
|
||||
{name : string; password : string;},
|
||||
{name : string; password : string;}
|
||||
> = new lib_plankton.zoo_form.class_form<
|
||||
{name : string; password : string;},
|
||||
{name : string; password : string;}
|
||||
>(
|
||||
x => x,
|
||||
x => x,
|
||||
new lib_plankton.zoo_input.class_input_group<
|
||||
{name : string; password : string;}
|
||||
>(
|
||||
[
|
||||
{
|
||||
"name": "name",
|
||||
"input": new lib_plankton.zoo_input.class_input_text(),
|
||||
"label": lib_plankton.translate.get("widget.login.internal.name"),
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"input": new lib_plankton.zoo_input.class_input_password(),
|
||||
"label": lib_plankton.translate.get("widget.login.internal.password"),
|
||||
},
|
||||
]
|
||||
),
|
||||
(
|
||||
[]
|
||||
.concat(
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("widget.login.internal.do"),
|
||||
"procedure": async (get_value, get_representation) => {
|
||||
const value : any = await get_value();
|
||||
try
|
||||
{
|
||||
await _dali.backend.session_begin(
|
||||
value.name,
|
||||
value.password
|
||||
);
|
||||
if (this.action_success !== null) this.action_success();
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
// todo
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
.concat(
|
||||
(this.action_cancel === null)
|
||||
?
|
||||
[]
|
||||
:
|
||||
[
|
||||
{
|
||||
"label": lib_plankton.translate.get("common.cancel"),
|
||||
"procedure": () => {
|
||||
this.action_cancel();
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
target_element.innerHTML = "";
|
||||
await form.setup(target_element);
|
||||
await form.input_write(
|
||||
{
|
||||
"name": this.initial_name,
|
||||
"password": "",
|
||||
}
|
||||
);
|
||||
form.input_focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_login_oidc
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private preparation_data : any;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_cancel : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_success : (null | (() => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
preparation_data : any,
|
||||
{
|
||||
"action_cancel": action_cancel = null,
|
||||
"action_success": action_success = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
action_cancel ?: (null | (() => void));
|
||||
action_success ?: (null | (() => void));
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.preparation_data = preparation_data;
|
||||
this.action_cancel = action_cancel;
|
||||
this.action_success = action_success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
// structure
|
||||
{
|
||||
target_element.innerHTML = await _dali.helpers.template_coin(
|
||||
"widget-login_oidc",
|
||||
"main",
|
||||
{
|
||||
"label": lib_plankton.string.coin(
|
||||
lib_plankton.translate.get("widget.login.oidc.via"),
|
||||
{
|
||||
"title": this.preparation_data.label,
|
||||
}
|
||||
),
|
||||
"href": this.preparation_data.url,
|
||||
"cancel": lib_plankton.translate.get("common.cancel"),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// controls
|
||||
{
|
||||
target_element.querySelector(".widget-login_oidc-cancel").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
this.action_cancel();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
.widget-login_oidc-cancel
|
||||
{
|
||||
display: block;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
<div class="widget-login_oidc">
|
||||
<a class="widget-login_oidc-link" href="{{href}}">{{label}}</a>
|
||||
<button class="widget-login_oidc-cancel">{{cancel}}</button>
|
||||
</div>
|
||||
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_entry_data = {
|
||||
label : string;
|
||||
groups : Array<string>;
|
||||
action : (() => void);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_menu implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private entries : Array<type_entry_data>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private initial_groups : Array<string>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private container : (null | HTMLElement);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
entries : Array<type_entry_data>,
|
||||
{
|
||||
"initial_groups": initial_groups = [],
|
||||
"initial_label": initial_label = "",
|
||||
}
|
||||
:
|
||||
{
|
||||
initial_groups ?: Array<string>;
|
||||
initial_label ?: string;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.entries = entries;
|
||||
this.initial_groups = initial_groups;
|
||||
this.label = initial_label;
|
||||
this.container = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public set_groups(
|
||||
groups : Array<string>
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.entries.forEach(
|
||||
(entry, index) => {
|
||||
const active : boolean = groups.some(group => entry.groups.includes(group));
|
||||
const rel : string = index.toFixed(0);
|
||||
const dom_entry = this.container.querySelector(".widget-menu-entry[rel=\"" + rel + "\"]");
|
||||
dom_entry.classList.toggle("widget-menu-entry-hidden", (! active));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public set_label(
|
||||
label : (null | string)
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.label = label;
|
||||
this.container.querySelector(".widget-menu-button").innerHTML = (
|
||||
(this.label === null)
|
||||
?
|
||||
("[" + "=" + "]")
|
||||
:
|
||||
("[" + this.label + "]")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private toggle_collapsed(
|
||||
{
|
||||
"mode": mode = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
mode ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.container.classList.toggle("widget-menu-collapsed", mode ?? undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
// structure
|
||||
this.container = await _dali.helpers.element_from_template(
|
||||
"widget-menu",
|
||||
"main",
|
||||
{
|
||||
"entries": (
|
||||
(
|
||||
await lib_plankton.call.promise_condense(
|
||||
this.entries.map(
|
||||
(entry, index) => () => _dali.helpers.template_coin(
|
||||
"widget-menu",
|
||||
"entry",
|
||||
{
|
||||
"label": entry.label,
|
||||
"rel": index.toFixed(0),
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.join("")
|
||||
),
|
||||
}
|
||||
);
|
||||
|
||||
// logic
|
||||
{
|
||||
// collapser
|
||||
{
|
||||
this.container.querySelector(".widget-menu-button").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
this.toggle_collapsed();
|
||||
}
|
||||
);
|
||||
}
|
||||
// entries
|
||||
{
|
||||
this.container.querySelectorAll(".widget-menu-entry").forEach(
|
||||
dom_entry => {
|
||||
dom_entry.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
const index : int = parseInt(dom_entry.getAttribute("rel"));
|
||||
const entry : type_entry_data = this.entries[index];
|
||||
this.toggle_collapsed({"mode": true});
|
||||
entry.action();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// init
|
||||
{
|
||||
this.toggle_collapsed({"mode": true});
|
||||
this.set_groups(this.initial_groups);
|
||||
this.set_label(null);
|
||||
}
|
||||
|
||||
// finish
|
||||
target_element.appendChild(this.container);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
.widget-menu
|
||||
{
|
||||
margin-left: auto;
|
||||
margin-right: 8px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.widget-menu.widget-menu-collapsed > .widget-menu-platform
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widget-menu-button
|
||||
{
|
||||
text-transform: initial;
|
||||
}
|
||||
|
||||
.widget-menu-entry
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.widget-menu-platform
|
||||
{
|
||||
background-color: hsl(var(--hue), 0%, 25%);
|
||||
|
||||
border-radius: 2px;
|
||||
border: 1px solid hsl(var(--hue), 0%, 0%);
|
||||
|
||||
padding: 8px;
|
||||
|
||||
/*
|
||||
min-width: 200px;
|
||||
*/
|
||||
}
|
||||
|
||||
.widget-menu-platform:not(.widget-menu-platform-collapsed)
|
||||
{
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 20px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.widget-menu-entries
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.widget-menu-entry
|
||||
{
|
||||
margin: 12px 8px;
|
||||
text-transform: capitalize;
|
||||
background-color: hsl(var(--hue), 0%, 25%);
|
||||
color: hsl(var(--hue), 0%, 100%);
|
||||
}
|
||||
|
||||
.widget-menu-entry:not(:hover) > span
|
||||
{
|
||||
border-bottom: 2px solid hsl(0, 0%, 25%);
|
||||
}
|
||||
|
||||
.widget-menu-entry:hover > span
|
||||
{
|
||||
border-bottom: 2px solid hsl(0, 0%, 100%);
|
||||
|
||||
transition: 1s ease color;
|
||||
}
|
||||
|
||||
.widget-menu-entry.widget-menu-entry-hidden
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<li class="widget-menu-entry" rel="{{rel}}">
|
||||
<span>{{label}}</span>
|
||||
</li>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<div class="widget-menu">
|
||||
<button class="widget-menu-button"></button>
|
||||
<div class="widget-menu-platform">
|
||||
<ul class="widget-menu-entries">
|
||||
{{entries}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_option = {
|
||||
mode : _dali.enum_view_mode;
|
||||
label : string,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_mode_switcher implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private options : Array<type_option>;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private initial_selection : (null | _dali.enum_view_mode);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_change : (null | ((mode : _dali.enum_view_mode) => void));
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
options : Array<type_option>,
|
||||
{
|
||||
"initial_selection": initial_selection = null,
|
||||
"action_change": action_change = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
initial_selection ?: (null | _dali.enum_view_mode),
|
||||
action_change ?: (null | ((mode : _dali.enum_view_mode) => void))
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.options = options;
|
||||
this.initial_selection = initial_selection;
|
||||
this.action_change = action_change;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
target_element.innerHTML = await _dali.helpers.template_coin(
|
||||
"widget-mode_switcher",
|
||||
"main",
|
||||
{
|
||||
"options": (await lib_plankton.call.promise_condense(
|
||||
this.options.map(
|
||||
option => () => _dali.helpers.template_coin(
|
||||
"widget-mode_switcher",
|
||||
"option",
|
||||
{
|
||||
"rel": _dali.view_mode_encode(option.mode),
|
||||
"value": _dali.view_mode_encode(option.mode),
|
||||
"label": option.label,
|
||||
}
|
||||
)
|
||||
)
|
||||
)).join(""),
|
||||
}
|
||||
);
|
||||
// initial selection
|
||||
{
|
||||
if (this.initial_selection !== null)
|
||||
{
|
||||
const selector : string = lib_plankton.string.coin(
|
||||
".widget-mode_switcher-option[rel=\"{{rel}}\"] > input",
|
||||
{
|
||||
"rel": _dali.view_mode_encode(this.initial_selection)
|
||||
}
|
||||
);
|
||||
(target_element.querySelector(selector) as HTMLInputElement).checked = true;
|
||||
}
|
||||
}
|
||||
// set listeners
|
||||
{
|
||||
if (this.action_change !== null)
|
||||
{
|
||||
target_element.querySelectorAll(".widget-mode_switcher-option").forEach(
|
||||
element => {
|
||||
const view_mode_encoded : string = element.getAttribute("rel");
|
||||
const mode : _dali.enum_view_mode = _dali.view_mode_decode(view_mode_encoded);
|
||||
element.querySelector("input").addEventListener(
|
||||
"change",
|
||||
(event) => {
|
||||
this.action_change(mode);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
.widget-mode_switcher-option
|
||||
{
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<div class="widget-mode_switcher">
|
||||
{{options}}
|
||||
</div>
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
<label class="widget-mode_switcher-option" rel="{{rel}}">
|
||||
<input type="radio" name="mode" value="{{value}}"/>
|
||||
<span>{{label}}</span>
|
||||
</label>
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_get_entries = (
|
||||
(
|
||||
from_pit : lib_plankton.pit.type_pit,
|
||||
to_pit : lib_plankton.pit.type_pit,
|
||||
calendar_ids : Array<_dali.type_calendar_id>
|
||||
)
|
||||
=>
|
||||
Promise<Array<_dali.type_event_object_extended>>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_create_event = (
|
||||
(
|
||||
stuff ?: {
|
||||
date ?: lib_plankton.pit.type_date;
|
||||
}
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_edit_event = (
|
||||
(
|
||||
event_key : _dali.type_event_key
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_multiview
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private initial_view_mode : _dali.enum_view_mode;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private weekview_initial_vertical : boolean;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private get_entries : type_get_entries;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_create_event : type_create_event;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_edit_event : type_edit_event;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private dom_context : (null | HTMLElement);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private widget_mode_switcher : _dali.widgets.class_widget_mode_switcher;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private widget_weekview : _dali.widgets.class_widget_weekview;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private widget_listview : _dali.widgets.class_widget_listview;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
get_entries : type_get_entries,
|
||||
{
|
||||
"initial_view_mode": initial_view_mode = _dali.enum_view_mode.week,
|
||||
"weekview_initial_vertical": weekview_initial_vertical = false,
|
||||
"action_create_event": action_create_event = ((stuff) => Promise.resolve<void>(undefined)),
|
||||
"action_edit_event": action_edit_event = ((event_key) => Promise.resolve<void>(undefined)),
|
||||
}
|
||||
:
|
||||
{
|
||||
initial_view_mode ?: _dali.enum_view_mode;
|
||||
weekview_initial_vertical ?: boolean;
|
||||
action_create_event ?: type_create_event;
|
||||
action_edit_event ?: type_edit_event;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.get_entries = get_entries;
|
||||
this.initial_view_mode = initial_view_mode;
|
||||
this.weekview_initial_vertical = weekview_initial_vertical;
|
||||
this.action_create_event = action_create_event;
|
||||
this.action_edit_event = action_edit_event;
|
||||
this.dom_context = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public toggle_calendar_visibilty(
|
||||
calendar_id : _dali.type_calendar_id,
|
||||
{
|
||||
"mode": mode = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
mode ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.widget_weekview.toggle_visibility(calendar_id, {"mode": mode});
|
||||
this.widget_listview.toggle_visibility(calendar_id, {"mode": mode});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private set_view_mode
|
||||
(
|
||||
view_mode : _dali.enum_view_mode
|
||||
)
|
||||
: void
|
||||
{
|
||||
this.dom_context.setAttribute("rel", _dali.view_mode_encode(view_mode));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public async update_entries(
|
||||
)
|
||||
:
|
||||
Promise<void>
|
||||
{
|
||||
await Promise.all(
|
||||
[
|
||||
this.widget_weekview.update_entries(),
|
||||
this.widget_listview.update_entries(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
this.dom_context = (target_element as HTMLElement);
|
||||
|
||||
this.dom_context.classList.add("widget-multiview");
|
||||
|
||||
// mode switcher
|
||||
{
|
||||
this.widget_mode_switcher = (
|
||||
new _dali.widgets.class_widget_mode_switcher(
|
||||
[
|
||||
{
|
||||
"mode": _dali.enum_view_mode.week,
|
||||
/**
|
||||
* @todo as dependency
|
||||
*/
|
||||
"label": lib_plankton.translate.get("widget.overview.mode.week"),
|
||||
},
|
||||
{
|
||||
"mode": _dali.enum_view_mode.list,
|
||||
/**
|
||||
* @todo as dependency
|
||||
*/
|
||||
"label": lib_plankton.translate.get("widget.overview.mode.list"),
|
||||
},
|
||||
],
|
||||
{
|
||||
"initial_selection": this.initial_view_mode,
|
||||
"action_change": (view_mode) => {
|
||||
this.set_view_mode(view_mode);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
let dom_wrapper = document.createElement("div");
|
||||
dom_wrapper.classList.add("widget-multiview-mode_switcher");
|
||||
await this.widget_mode_switcher.load(dom_wrapper);
|
||||
this.dom_context.appendChild(dom_wrapper);
|
||||
}
|
||||
// weekview
|
||||
{
|
||||
this.widget_weekview = (
|
||||
new _dali.widgets.class_widget_weekview(
|
||||
this.get_entries,
|
||||
{
|
||||
"action_select_event": (event_key) => this.action_edit_event(event_key),
|
||||
"action_select_day": (date) => this.action_create_event({"date": date}),
|
||||
"vertical": this.weekview_initial_vertical,
|
||||
}
|
||||
)
|
||||
);
|
||||
let dom_wrapper = document.createElement("div");
|
||||
dom_wrapper.classList.add("widget-multiview-weekview");
|
||||
await this.widget_weekview.load(dom_wrapper);
|
||||
this.dom_context.appendChild(dom_wrapper);
|
||||
}
|
||||
// listview
|
||||
{
|
||||
this.widget_listview = (
|
||||
new _dali.widgets.class_widget_listview(
|
||||
this.get_entries,
|
||||
{
|
||||
"action_select": (event_key) => this.action_edit_event(event_key),
|
||||
"action_add": () => this.action_create_event(),
|
||||
}
|
||||
)
|
||||
);
|
||||
let dom_wrapper = document.createElement("div");
|
||||
dom_wrapper.classList.add("widget-multiview-listview");
|
||||
await this.widget_listview.load(dom_wrapper);
|
||||
this.dom_context.appendChild(dom_wrapper);
|
||||
}
|
||||
this.set_view_mode(this.initial_view_mode);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
.widget-multiview-mode_switcher
|
||||
{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.widget-multiview[rel="week"] > .widget-multiview-weekview {}
|
||||
.widget-multiview[rel="week"] > .widget-multiview-listview {display: none;}
|
||||
|
||||
.widget-multiview[rel="list"] > .widget-multiview-weekview {display: none;}
|
||||
.widget-multiview[rel="list"] > .widget-multiview-listview {}
|
||||
|
|
@ -1,648 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_action_create_calendar = (
|
||||
(
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_action_edit_calendar = (
|
||||
(
|
||||
type_calendar_object_reduced_with_id
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_action_create_event = (
|
||||
(
|
||||
stuff ?: {
|
||||
date ?: lib_plankton.pit.type_date;
|
||||
}
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_action_edit_event = (
|
||||
(
|
||||
event_key : _dali.type_event_key
|
||||
)
|
||||
=>
|
||||
Promise<void>
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_overview
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private widget_sources : _dali.widgets.class_widget_sources;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private widget_multiview : _dali.widgets.class_widget_multiview;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_create_calendar : type_action_create_calendar;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_edit_calendar : type_action_edit_calendar;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_create_event : type_action_create_event;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_edit_event : type_action_edit_event;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
)
|
||||
{
|
||||
this.action_create_calendar = async (
|
||||
) => {
|
||||
const widget = new _dali.widgets.class_widget_calendar_edit(
|
||||
await _dali.model.group_list(),
|
||||
await _dali.model.user_list(),
|
||||
{
|
||||
"name": "",
|
||||
"hue": lib_plankton.random.generate_unit(),
|
||||
"access": {
|
||||
"public": false,
|
||||
"default_level": _dali.enum_access_level.none,
|
||||
"attributed_group": lib_plankton.map.hashmap.implementation_map<
|
||||
_dali.type_group_id,
|
||||
_dali.enum_access_level
|
||||
>(
|
||||
lib_plankton.map.hashmap.make<
|
||||
_dali.type_group_id,
|
||||
_dali.enum_access_level
|
||||
>(
|
||||
group_id => group_id.toFixed(0),
|
||||
)
|
||||
),
|
||||
"attributed_user": lib_plankton.map.hashmap.implementation_map<
|
||||
_dali.type_user_id,
|
||||
_dali.enum_access_level
|
||||
>(
|
||||
lib_plankton.map.hashmap.make<
|
||||
_dali.type_user_id,
|
||||
_dali.enum_access_level
|
||||
>(
|
||||
user_id => user_id.toFixed(0),
|
||||
)
|
||||
),
|
||||
},
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
"resource_id": 0,
|
||||
},
|
||||
{
|
||||
"read_only": false,
|
||||
"action_cancel": () => {
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
},
|
||||
"action_add": (calendar_object) => {
|
||||
_dali.model.calendar_add(
|
||||
calendar_object
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_sources_and_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
(reason) => {
|
||||
lib_plankton.log.warning(
|
||||
"dali.overview.calendar_add_error",
|
||||
{"reason": String(reason)}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
_dali.overlay.clear();
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
};
|
||||
this.action_edit_calendar = async (
|
||||
calendar_object_reduced_with_id
|
||||
) => {
|
||||
const read_only : boolean = (() => {
|
||||
switch (calendar_object_reduced_with_id.access_level)
|
||||
{
|
||||
case _dali.enum_access_level.none:
|
||||
{
|
||||
throw (new Error("this event should not be visible"));
|
||||
break;
|
||||
}
|
||||
case _dali.enum_access_level.edit:
|
||||
case _dali.enum_access_level.view:
|
||||
{
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case _dali.enum_access_level.admin:
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}) ();
|
||||
if (read_only)
|
||||
{
|
||||
lib_plankton.log.notice(
|
||||
"dali.overview.may_not_edit_calendar",
|
||||
{
|
||||
"calendar_id": calendar_object_reduced_with_id.id,
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
const calendar_id : _dali.type_calendar_id = calendar_object_reduced_with_id.id;
|
||||
const calendar_object : _dali.type_calendar_object = await _dali.model.calendar_get(
|
||||
calendar_id
|
||||
);
|
||||
const widget = new _dali.widgets.class_widget_calendar_edit(
|
||||
await _dali.model.group_list(),
|
||||
await _dali.model.user_list(),
|
||||
calendar_object,
|
||||
{
|
||||
"read_only": read_only,
|
||||
"action_cancel": () => {
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
},
|
||||
"action_change": (data) => {
|
||||
_dali.model.calendar_change(
|
||||
calendar_id,
|
||||
data
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_sources_and_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
);
|
||||
},
|
||||
"action_remove": (data) => {
|
||||
_dali.model.calendar_remove(
|
||||
calendar_id
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_sources_and_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
_dali.overlay.clear();
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @todo unterschiedliches Verhalten bei Anmeldung?
|
||||
*/
|
||||
this.action_create_event = async (
|
||||
{
|
||||
"date": date = lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date,
|
||||
}
|
||||
:
|
||||
{
|
||||
date ?: lib_plankton.pit.type_date;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
) => {
|
||||
if (! _dali.is_logged_in())
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const widget = new _dali.widgets.class_widget_event_edit(
|
||||
(await this.get_available_calendars()),
|
||||
{
|
||||
"calendar_id": null,
|
||||
"event_name": "",
|
||||
"event_begin": lib_plankton.call.convey(
|
||||
date,
|
||||
[
|
||||
x => ({
|
||||
"timezone_shift": 0,
|
||||
"date": date,
|
||||
"time": {"hour": 12, "minute": 0, "second": 0}
|
||||
}),
|
||||
lib_plankton.pit.from_datetime,
|
||||
x => lib_plankton.pit.shift_hour(x, 0),
|
||||
lib_plankton.pit.to_datetime,
|
||||
]
|
||||
),
|
||||
"event_end": lib_plankton.call.convey(
|
||||
date,
|
||||
[
|
||||
x => ({
|
||||
"timezone_shift": 0,
|
||||
"date": date,
|
||||
"time": {"hour": 12, "minute": 0, "second": 0}
|
||||
}),
|
||||
lib_plankton.pit.from_datetime,
|
||||
x => lib_plankton.pit.shift_hour(x, +1),
|
||||
lib_plankton.pit.to_datetime,
|
||||
]
|
||||
),
|
||||
"event_location": null,
|
||||
"event_link": null,
|
||||
"event_description": null,
|
||||
},
|
||||
{
|
||||
"read_only": false,
|
||||
"action_cancel": () => {
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
},
|
||||
"action_add": (data) => {
|
||||
_dali.model.event_add(
|
||||
data.calendar_id,
|
||||
{
|
||||
"name": data.event_name,
|
||||
"begin": data.event_begin,
|
||||
"end": data.event_end,
|
||||
"location": data.event_location,
|
||||
"link": data.event_link,
|
||||
"description": data.event_description,
|
||||
}
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
(reason) => {
|
||||
// todo
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
_dali.overlay.clear();
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
}
|
||||
}
|
||||
/**
|
||||
*/
|
||||
this.action_edit_event = async (
|
||||
event_key
|
||||
) => {
|
||||
const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key);
|
||||
const read_only : boolean = (() => {
|
||||
switch (event_object_extended.access_level)
|
||||
{
|
||||
case _dali.enum_access_level.none:
|
||||
{
|
||||
throw (new Error("this event should not be visible"));
|
||||
break;
|
||||
}
|
||||
case _dali.enum_access_level.view:
|
||||
{
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case _dali.enum_access_level.edit:
|
||||
case _dali.enum_access_level.admin:
|
||||
{
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}) ();
|
||||
const widget = new _dali.widgets.class_widget_event_edit(
|
||||
(await this.get_available_calendars()),
|
||||
{
|
||||
"calendar_id": event_object_extended.calendar_id,
|
||||
"event_name": event_object_extended.event_object.name,
|
||||
"event_begin": event_object_extended.event_object.begin,
|
||||
"event_end": event_object_extended.event_object.end,
|
||||
"event_location": event_object_extended.event_object.location,
|
||||
"event_link": event_object_extended.event_object.link,
|
||||
"event_description": event_object_extended.event_object.description,
|
||||
},
|
||||
{
|
||||
"read_only": read_only,
|
||||
"action_cancel": () => {
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
},
|
||||
"action_change": (data) => {
|
||||
_dali.model.event_change(
|
||||
event_key,
|
||||
{
|
||||
"name": data.event_name,
|
||||
"begin": data.event_begin,
|
||||
"end": data.event_end,
|
||||
"location": data.event_location,
|
||||
"link": data.event_link,
|
||||
"description": data.event_description,
|
||||
}
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
(reason) => {
|
||||
lib_plankton.log.warning(
|
||||
"dali.overview.event_change.error",
|
||||
{"reason": String(reason)}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
"action_remove": () => {
|
||||
_dali.model.event_remove(
|
||||
event_key
|
||||
)
|
||||
.then(
|
||||
() => {
|
||||
this.update_entries();
|
||||
_dali.overlay.toggle({"mode": false});
|
||||
}
|
||||
)
|
||||
.catch(
|
||||
(reason) => {
|
||||
lib_plankton.log.warning(
|
||||
"dali.overview.event_remove_error",
|
||||
{"reason": String(reason)}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
_dali.overlay.clear();
|
||||
_dali.overlay.toggle({"mode": true});
|
||||
await widget.load(_dali.overlay.get_content_element());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private async get_available_calendars(
|
||||
)
|
||||
: Promise<
|
||||
Array<
|
||||
_dali.type_calendar_object_reduced_with_id
|
||||
>
|
||||
>
|
||||
{
|
||||
return (
|
||||
(await _dali.model.calendar_list())
|
||||
/*
|
||||
.filter(
|
||||
(entry) => (
|
||||
(entry.access_level === _dali.enum_access_level.edit)
|
||||
||
|
||||
(entry.access_level === _dali.enum_access_level.admin)
|
||||
)
|
||||
)
|
||||
*/
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private async get_entries(
|
||||
from_pit : lib_plankton.pit.type_pit,
|
||||
to_pit : lib_plankton.pit.type_pit,
|
||||
calendar_ids : Array<_dali.type_calendar_id>
|
||||
)
|
||||
: Promise<Array<_dali.type_event_object_extended>>
|
||||
{
|
||||
/**
|
||||
* @todo do NOT wait?
|
||||
*/
|
||||
await _dali.model.sync_events(
|
||||
{
|
||||
"from": from_pit,
|
||||
"to": to_pit,
|
||||
},
|
||||
{
|
||||
"calendar_ids": calendar_ids,
|
||||
}
|
||||
);
|
||||
/**
|
||||
* @todo filter
|
||||
*/
|
||||
return _dali.model.event_list();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private async update_sources_and_entries(
|
||||
{
|
||||
"priviliged": priviliged = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
priviliged ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
await this.widget_sources.update({"priviliged": priviliged});
|
||||
await this.widget_multiview.update_entries();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo use priviliged?
|
||||
*/
|
||||
private async update_entries(
|
||||
{
|
||||
"priviliged": priviliged = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
priviliged ?: (null | boolean);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
await this.widget_multiview.update_entries();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const view_mode : _dali.enum_view_mode = _dali.helpers.view_mode_determine("auto");
|
||||
const view_kind : _dali.enum_view_kind = _dali.helpers.view_kind_determine("auto");
|
||||
|
||||
this.widget_sources = (
|
||||
new _dali.widgets.class_widget_sources(
|
||||
_dali.model.calendar_list,
|
||||
{
|
||||
"initial_priviliged": _dali.is_logged_in(),
|
||||
"action_add": this.action_create_calendar,
|
||||
"action_select": this.action_edit_calendar,
|
||||
"action_toggle": (entry, mode) => {
|
||||
this.widget_multiview.toggle_calendar_visibilty(entry.id, {"mode": mode});
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
this.widget_multiview = (
|
||||
new _dali.widgets.class_widget_multiview(
|
||||
this.get_entries,
|
||||
{
|
||||
"initial_view_mode": view_mode,
|
||||
"weekview_initial_vertical": (view_kind === _dali.enum_view_kind.touch),
|
||||
"action_create_event": this.action_create_event,
|
||||
"action_edit_event": this.action_edit_event,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
target_element.innerHTML = await _dali.helpers.template_coin(
|
||||
"widget-overview",
|
||||
"main",
|
||||
{
|
||||
}
|
||||
);
|
||||
|
||||
// head
|
||||
{
|
||||
// hint
|
||||
{
|
||||
const dom_hint = target_element.querySelector(".widget-overview-hint");
|
||||
dom_hint.textContent = lib_plankton.translate.get("widget.overview.login_hint");
|
||||
dom_hint.classList.toggle("widget-overview-hint-hidden", _dali.is_logged_in());
|
||||
}
|
||||
}
|
||||
// body
|
||||
{
|
||||
let widget_slider : lib_plankton.zoo_widget.interface_widget;
|
||||
switch (view_kind)
|
||||
{
|
||||
case _dali.enum_view_kind.regular:
|
||||
{
|
||||
widget_slider = new lib_plankton.zoo_widget.class_slider(
|
||||
[
|
||||
new lib_plankton.zoo_widget.class_bunch(
|
||||
[
|
||||
this.widget_sources,
|
||||
this.widget_multiview,
|
||||
]
|
||||
),
|
||||
],
|
||||
{
|
||||
"threshold": 100,
|
||||
"initial_index": 1,
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case _dali.enum_view_kind.touch:
|
||||
{
|
||||
widget_slider = new lib_plankton.zoo_widget.class_slider(
|
||||
[
|
||||
this.widget_sources,
|
||||
this.widget_multiview,
|
||||
],
|
||||
{
|
||||
"threshold": 100,
|
||||
"initial_index": 2,
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
await widget_slider.load(target_element.querySelector(".widget-overview-body"));
|
||||
}
|
||||
|
||||
_dali.model.listen_reset(
|
||||
async (priviliged) => {
|
||||
this.update_sources_and_entries({"priviliged": priviliged});
|
||||
target_element.querySelector(".widget-overview-hint").classList.toggle("widget-overview-hint-hidden", priviliged);
|
||||
}
|
||||
);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
.widget-overview-head
|
||||
{
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 12px;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.widget-overview-hint
|
||||
{
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.widget-overview-hint.widget-overview-hint-hidden
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widget-overview-body
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.widget-overview-pane-left
|
||||
{
|
||||
flex-basis: 12.5%;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.widget-overview-pane-right
|
||||
{
|
||||
flex-basis: 87.5%;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.widget-overview-body .widget-slider-slide .widget-bunch
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.widget-overview-body .widget-slider-slide .widget-bunch-element:nth-child(1)
|
||||
{
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: 12.5%;
|
||||
}
|
||||
|
||||
.widget-overview-body .widget-slider-slide .widget-bunch-element:nth-child(2)
|
||||
{
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: 87.5%;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<div class="widget-overview">
|
||||
<div class="widget-overview-head">
|
||||
<div class="widget-overview-hint">
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-overview-body">
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,198 +1,124 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
namespace _zeitbild.frontend_web.widgets.sources
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
type type_entry = {
|
||||
id : _dali.type_calendar_id;
|
||||
id : _zeitbild.frontend_web.type.calendar_id;
|
||||
name : string;
|
||||
hue : float;
|
||||
access_level : _dali.enum_access_level;
|
||||
access_level : _zeitbild.frontend_web.type.enum_access_level;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_sources implements lib_plankton.zoo_widget.interface_widget
|
||||
export class class_widget_sources extends _zeitbild.class_widget
|
||||
{
|
||||
|
||||
/**
|
||||
* [dependency]
|
||||
*/
|
||||
private get_entries : (() => Promise<Array<type_entry>>);
|
||||
private keys : Array<string>;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_toggle : ((entry : type_entry, mode : boolean) => void);
|
||||
private data : Record<string, type_entry>;
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_select : ((entry : type_entry) => void);
|
||||
private action_open : ((entry : type_entry) => void);
|
||||
|
||||
|
||||
/**
|
||||
* [hook]
|
||||
*/
|
||||
private action_add : (() => void);
|
||||
|
||||
|
||||
/**
|
||||
* [state]
|
||||
*/
|
||||
private priviliged : boolean;
|
||||
|
||||
|
||||
/**
|
||||
* [state]
|
||||
*/
|
||||
private container : (null | Element);
|
||||
private action_toggle_visibility : ((entry : type_entry) => void);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
get_entries : (() => Promise<Array<type_entry>>),
|
||||
{
|
||||
"action_select": action_select = ((calendar_id) => {}),
|
||||
"action_toggle": action_toggle = ((calendar_id, mode) => {}),
|
||||
"action_add": action_add = (() => {}),
|
||||
"initial_priviliged": initial_priviliged = false,
|
||||
}
|
||||
:
|
||||
{
|
||||
action_select ?: ((entry : type_entry) => void);
|
||||
action_toggle ?: ((entry : type_entry, mode : boolean) => void);
|
||||
action_add ?: (() => void);
|
||||
initial_priviliged ?: boolean;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
entries : Array<type_entry>,
|
||||
options : {
|
||||
action_open ?: ((entry : type_entry) => void);
|
||||
action_toggle_visibility ?: ((entry : type_entry) => void);
|
||||
} = {}
|
||||
)
|
||||
{
|
||||
// dependencies
|
||||
this.get_entries = get_entries;
|
||||
|
||||
// hooks
|
||||
this.action_select = action_select;
|
||||
this.action_toggle = action_toggle;
|
||||
this.action_add = action_add;
|
||||
|
||||
// state
|
||||
this.priviliged = initial_priviliged;
|
||||
this.container = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private static id_encode(
|
||||
id : _dali.type_calendar_id
|
||||
)
|
||||
: string
|
||||
options = Object.assign(
|
||||
{
|
||||
return id.toFixed(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private static id_decode(
|
||||
representation : string
|
||||
)
|
||||
: _dali.type_calendar_id
|
||||
{
|
||||
return parseInt(representation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public async update(
|
||||
{
|
||||
"priviliged": priviliged = null,
|
||||
}
|
||||
:
|
||||
{
|
||||
priviliged ?: boolean;
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
if (priviliged === null)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
this.priviliged = priviliged;
|
||||
}
|
||||
const data : lib_plankton.map.type_map<_dali.type_calendar_id, type_entry> = lib_plankton.map.hashmap.implementation_map(
|
||||
lib_plankton.map.hashmap.make(
|
||||
calendar_id => class_widget_sources.id_encode(calendar_id),
|
||||
{
|
||||
"pairs": (
|
||||
(await this.get_entries())
|
||||
.map(
|
||||
entry => (
|
||||
{
|
||||
"key": entry.id,
|
||||
"value": entry,
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
"action_open": (calendar_id) => {},
|
||||
"action_toggle_visibility": (calendar_id) => {},
|
||||
},
|
||||
options
|
||||
);
|
||||
// structure
|
||||
super();
|
||||
this.keys = [];
|
||||
this.data = {};
|
||||
entries.forEach(
|
||||
(entry) => {
|
||||
const key : string = entry.id.toFixed(0);
|
||||
this.keys.push(key);
|
||||
this.data[key] = entry;
|
||||
}
|
||||
);
|
||||
this.action_open = options.action_open;
|
||||
this.action_toggle_visibility = options.action_toggle_visibility;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
) : Promise<void>
|
||||
{
|
||||
this.container.innerHTML = await _dali.helpers.template_coin(
|
||||
target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin(
|
||||
"widget-sources",
|
||||
"main",
|
||||
{
|
||||
"label_create": lib_plankton.translate.get("widget.sources.create"),
|
||||
"entries": (
|
||||
(
|
||||
await _dali.helpers.promise_row<string>(
|
||||
lib_plankton.map.dump(data)
|
||||
await _zeitbild.frontend_web.helpers.promise_row<string>(
|
||||
this.keys
|
||||
.map(
|
||||
(pair) => () => {
|
||||
return _dali.helpers.template_coin(
|
||||
(key) => () => {
|
||||
const entry : type_entry = this.data[key];
|
||||
return _zeitbild.frontend_web.helpers.template_coin(
|
||||
"widget-sources",
|
||||
"entry",
|
||||
{
|
||||
"name": pair.value.name,
|
||||
"name": entry.name,
|
||||
"label_toggle": lib_plankton.string.coin(
|
||||
"{{show}}/{{hide}}",
|
||||
{
|
||||
"show": lib_plankton.translate.get("common.show"),
|
||||
"hide": lib_plankton.translate.get("common.hide"),
|
||||
}
|
||||
),
|
||||
"label_edit": lib_plankton.translate.get("common.edit"),
|
||||
// "access_level": entry.access_level, // TODO
|
||||
"color": _dali.helpers.event_color(pair.value.hue),
|
||||
"rel": class_widget_sources.id_encode(pair.key),
|
||||
// TODO centralize
|
||||
"color_head": lib_plankton.color.output_hex(
|
||||
lib_plankton.color.give_generic(
|
||||
(entry.id - 1),
|
||||
{
|
||||
"saturation": 0.375,
|
||||
"value": 0.375,
|
||||
}
|
||||
),
|
||||
),
|
||||
"color_body": lib_plankton.color.output_hex(
|
||||
lib_plankton.color.give_generic(
|
||||
(entry.id - 1),
|
||||
{
|
||||
"saturation": 0.375,
|
||||
"value": 0.25,
|
||||
}
|
||||
),
|
||||
),
|
||||
"rel": key,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -203,66 +129,43 @@ namespace _dali.widgets
|
|||
),
|
||||
}
|
||||
);
|
||||
this.container.querySelector(".sources").classList.toggle("sources-priviliged", this.priviliged);
|
||||
}
|
||||
// listeners
|
||||
{
|
||||
this.container.querySelector(".sources-create").addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
this.action_add();
|
||||
}
|
||||
);
|
||||
this.container.querySelectorAll(".sources-entry-visibility").forEach(
|
||||
target_element.querySelectorAll(".sources-entry-head").forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"change",
|
||||
"click",
|
||||
(event) => {
|
||||
element.parentElement.classList.toggle("sources-entry-open");
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
target_element.querySelectorAll(".sources-entry-toggle").forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
const mode : boolean = (element as HTMLInputElement).checked;
|
||||
const key_encoded : string = element.parentElement.getAttribute("rel");
|
||||
const calendar_id : _dali.type_calendar_id = class_widget_sources.id_decode(key_encoded);
|
||||
const entry : type_entry = data.get(calendar_id);
|
||||
element.parentElement.classList.toggle("sources-entry-hidden", (! mode));
|
||||
this.action_toggle(entry, mode);
|
||||
const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
|
||||
const entry : type_entry = this.data[key];
|
||||
element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-hidden");
|
||||
element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-open", false);
|
||||
this.action_toggle_visibility(entry);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
this.container.querySelectorAll(".sources-entry").forEach(
|
||||
target_element.querySelectorAll(".sources-entry-edit").forEach(
|
||||
(element) => {
|
||||
element.addEventListener(
|
||||
"click",
|
||||
(event) => {
|
||||
if ((event.target as Element).classList.contains("sources-entry-visibility"))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
const key_encoded : string = element.getAttribute("rel");
|
||||
const calendar_id : _dali.type_calendar_id = class_widget_sources.id_decode(key_encoded);
|
||||
const entry : type_entry = data.get(calendar_id);
|
||||
this.action_select(entry);
|
||||
}
|
||||
const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
|
||||
const entry : type_entry = this.data[key];
|
||||
this.action_open(entry);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : Element
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
this.container = target_element;
|
||||
await this.update();
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
.sources
|
||||
{
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.sources:not(.sources-priviliged) > .sources-create
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sources-create
|
||||
{
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.sources-entries
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.sources-entry
|
||||
{
|
||||
margin: 8px;
|
||||
padding: 4px;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
.sources-entry-hidden
|
||||
{
|
||||
filter: saturate(0);
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
<li class="sources-entry" style="background-color: {{color}}" rel="{{rel}}">
|
||||
<input class="sources-entry-visibility" type="checkbox" checked="checked"/>
|
||||
<span class="sources-entry-name">{{name}}</span>
|
||||
<li class="sources-entry" style="background-color: {{color_head}}" rel="{{rel}}">
|
||||
<div class="sources-entry-head">
|
||||
<span>{{name}}</span>
|
||||
</div>
|
||||
<div class="sources-entry-body" style="background-color: {{color_body}}">
|
||||
<ul>
|
||||
<li class="sources-entry-action sources-entry-toggle">{{label_toggle}}</li>
|
||||
<li class="sources-entry-action sources-entry-edit">{{label_edit}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
<div class="sources">
|
||||
<ul class="sources-entries">
|
||||
<ul class="sources">
|
||||
{{entries}}
|
||||
</ul>
|
||||
<a class="sources-create" href="">{{label_create}}</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
This file is part of »dali«.
|
||||
|
||||
Copyright 2025 'kcf' <fenris@folksprak.org>
|
||||
|
||||
»dali« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»dali« is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »dali«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace _dali.widgets
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export class class_widget_special_number_input
|
||||
implements lib_plankton.zoo_widget.interface_widget
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
private action_change : ((int) => Promise<void>);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private label : (null | string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private minimum : (null | int);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private maximum : (null | int);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
private value : int;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public constructor(
|
||||
{
|
||||
"label": label = null,
|
||||
"minimum": minimum = null,
|
||||
"maximum": maximum = null,
|
||||
"initial_value": initial_value = 0,
|
||||
"action_change": action_change = ((value) => Promise.resolve<void>(undefined)),
|
||||
}
|
||||
:
|
||||
{
|
||||
label ?: (null | string);
|
||||
minimum ?: (null | int);
|
||||
maximum ?: (null | int);
|
||||
initial_value ?: int;
|
||||
action_change ?: ((int) => Promise<void>);
|
||||
}
|
||||
=
|
||||
{
|
||||
}
|
||||
)
|
||||
{
|
||||
this.label = label;
|
||||
this.minimum = minimum;
|
||||
this.maximum = maximum;
|
||||
this.value = initial_value;
|
||||
this.action_change = action_change;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [implementation]
|
||||
*/
|
||||
public async load(
|
||||
target_element : HTMLElement
|
||||
)
|
||||
: Promise<void>
|
||||
{
|
||||
const dom_root = await _dali.helpers.element_from_template(
|
||||
"widget-special_number_input",
|
||||
"main",
|
||||
{
|
||||
"label": this.label,
|
||||
}
|
||||
);
|
||||
|
||||
const dom_input : HTMLInputElement = (dom_root.querySelector(".widget-special_number_input-input") as HTMLInputElement);
|
||||
|
||||
// listeners
|
||||
{
|
||||
dom_input.addEventListener(
|
||||
"change",
|
||||
() => {
|
||||
const value : int = parseInt(dom_input.value);
|
||||
if (
|
||||
((this.minimum === null) || (value >= this.minimum))
|
||||
&&
|
||||
((this.maximum === null) || (value <= this.maximum))
|
||||
)
|
||||
{
|
||||
this.value = value;
|
||||
this.action_change(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
);
|
||||
dom_root.querySelector(".widget-special_number_input-prev").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
if ((this.minimum === null) || (this.value > this.minimum))
|
||||
{
|
||||
this.value -= 1;
|
||||
dom_input.value = this.value.toFixed(0);
|
||||
this.action_change(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
);
|
||||
dom_root.querySelector(".widget-special_number_input-next").addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
if ((this.maximum === null) || (this.value < this.maximum))
|
||||
{
|
||||
this.value += 1;
|
||||
dom_input.value = this.value.toFixed(0);
|
||||
this.action_change(this.value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// content
|
||||
{
|
||||
dom_input.value = this.value.toFixed(0);
|
||||
}
|
||||
|
||||
target_element.appendChild(dom_root);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
.widget-special_number_input-controls
|
||||
{
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.widget-special_number_input-controls > *
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.widget-special_number_input-button
|
||||
{
|
||||
padding: 4px 4px;
|
||||
margin: 0;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.widget-special_number_input-label
|
||||
{
|
||||
display: block;
|
||||
|
||||
font-size: 0.75em;
|
||||
/*
|
||||
text-transform: uppercase;
|
||||
*/
|
||||
}
|
||||
|
||||
.widget-special_number_input-input
|
||||
{
|
||||
max-width: 40px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<div class="widget-special_number_input">
|
||||
<label class="widget-special_number_input-label">{{label}}</label>
|
||||
<div class="widget-special_number_input-controls">
|
||||
<div class="widget-special_number_input-button widget-special_number_input-prev">◂</div>
|
||||
<input type="text" class="widget-special_number_input-input" pattern="-?[0-9]+"/>
|
||||
<div class="widget-special_number_input-button widget-special_number_input-next">▸</div>
|
||||
</div>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
|||
<div class="weekview-control weekview-control-vertical">
|
||||
<label class="weekview-control-label">{{label}}</label>
|
||||
<div class="weekview-control-input">
|
||||
<input type="checkbox"/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,9 +1,32 @@
|
|||
<div class="weekview">
|
||||
<div class="weekview-controls">
|
||||
<label class="weekview-control weekview-control-year">
|
||||
<span>{{label_control_year}}</span>
|
||||
<input type="number"/>
|
||||
</label>
|
||||
<label class="weekview-control weekview-control-week">
|
||||
<span>{{label_control_week}}</span>
|
||||
<input type="number"/>
|
||||
</label>
|
||||
<label class="weekview-control weekview-control-count">
|
||||
<span>{{label_control_count}}</span>
|
||||
<input type="number"/>
|
||||
</label>
|
||||
<input type="submit" class="weekview-control weekview-control-apply" value="{{label_control_apply}}"/>
|
||||
</div>
|
||||
<div class="weekview-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="calendar-cell"></th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_monday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_tuesday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_wednesday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_thursday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_friday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_saturday}}</th>
|
||||
<th class="calendar-cell calendar-cell-day">{{label_weekday_sunday}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<li class="weekview-event_entry{{additional_classes}}" style="background-color: {{color}};" rel="{{rel}}">
|
||||
<li class="weekview-event_entry{{additional_classes}}" style="background-color: {{color}};" title="{{title}}" rel="{{rel}}">
|
||||
{{name}}
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<td class="weekview-cell weekview-cell-regular{{extra_classes}}" rel="{{rel}}">
|
||||
<span class="weekview-day">
|
||||
<span class="weekview-day" title="{{title}}">
|
||||
{{day}}
|
||||
</span>
|
||||
<ul class="weekview-events">
|
||||
|
|
|
|||
10
tools/build
10
tools/build
|
|
@ -24,24 +24,16 @@ def main():
|
|||
metavar = "<conf-path>",
|
||||
help = "conf path",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-f",
|
||||
"--force",
|
||||
action = 'store_true',
|
||||
default = False,
|
||||
help = "force",
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
targets = []
|
||||
targets.append("default")
|
||||
_os.system(
|
||||
"make dir_build=%s --file=tools/makefile %s%s"
|
||||
"make dir_build=%s --file=tools/makefile %s"
|
||||
% (
|
||||
args.output_directory,
|
||||
" ".join(targets),
|
||||
(" --always-make" if args.force else ""),
|
||||
)
|
||||
)
|
||||
if True:
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ def main():
|
|||
"--target-directory",
|
||||
type = str,
|
||||
dest = "target_directory",
|
||||
default = "/opt/dali",
|
||||
default = "/opt/zbwf",
|
||||
metavar = "<target-directory>",
|
||||
help = "directory on the target system, where the files shall be put; default: /opt/dali",
|
||||
help = "directory on the target system, where the files shall be put; default: /opt/zbwf",
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-b",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ def main(
|
|||
dest = "index_template_path",
|
||||
type = str,
|
||||
)
|
||||
argument_parser.add_argument(
|
||||
"-t",
|
||||
"--template",
|
||||
dest = "template_paths",
|
||||
type = str,
|
||||
action = "append",
|
||||
default = []
|
||||
)
|
||||
args = argument_parser.parse_args()
|
||||
|
||||
## exec
|
||||
|
|
@ -38,6 +46,12 @@ def main(
|
|||
string_coin(
|
||||
file_read(args.index_template_path),
|
||||
{
|
||||
"templates": "".join(
|
||||
map(
|
||||
file_read,
|
||||
args.template_paths
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
|||
162
tools/makefile
162
tools/makefile
|
|
@ -26,123 +26,123 @@ ${dir_build}/index.html: \
|
|||
${dir_source}/index.html.tpl
|
||||
@ ${cmd_log} "index …"
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ tools/make-index ${dir_source}/index.html.tpl > $@
|
||||
@ tools/make-index \
|
||||
${dir_source}/index.html.tpl \
|
||||
> $@
|
||||
|
||||
.PHONY: templates
|
||||
templates: \
|
||||
templates-widgets-special_number_input \
|
||||
templates-widgets-login_oidc \
|
||||
templates-widgets-menu \
|
||||
templates-widgets-sources \
|
||||
templates-widgets-calendar_edit \
|
||||
templates-widgets-event_edit \
|
||||
templates-widgets-caldav \
|
||||
templates-widgets-listview \
|
||||
templates-widgets-weekview \
|
||||
templates-widgets-overview \
|
||||
templates-widgets-mode_switcher
|
||||
|
||||
.PHONY: templates-widgets-special_number_input
|
||||
templates-widgets-special_number_input: \
|
||||
$(wildcard ${dir_source}/widgets/special_number_input/templates/*)
|
||||
@ ${cmd_log} "templates:widget:special_number_input …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-special_number_input
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/special_number_input/templates/* ${dir_build}/templates/widget-special_number_input/
|
||||
|
||||
.PHONY: templates-widgets-login_oidc
|
||||
templates-widgets-login_oidc: \
|
||||
$(wildcard ${dir_source}/widgets/login_oidc/templates/*)
|
||||
@ ${cmd_log} "templates:widget:login_oidc …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-login_oidc
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/login_oidc/templates/* ${dir_build}/templates/widget-login_oidc/
|
||||
|
||||
.PHONY: templates-widgets-menu
|
||||
templates-widgets-menu: \
|
||||
$(wildcard ${dir_source}/widgets/menu/templates/*)
|
||||
@ ${cmd_log} "templates:widget:menu …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-menu
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/menu/templates/* ${dir_build}/templates/widget-menu/
|
||||
templates-pages-caldav \
|
||||
templates-pages-calendar_add \
|
||||
templates-pages-calendar_edit \
|
||||
templates-pages-event_add \
|
||||
templates-pages-event_edit \
|
||||
templates-pages-overview \
|
||||
templates-pages-login
|
||||
|
||||
.PHONY: templates-widgets-sources
|
||||
templates-widgets-sources: \
|
||||
$(wildcard ${dir_source}/widgets/sources/templates/*)
|
||||
@ ${cmd_log} "templates:widget:sources …"
|
||||
@ ${cmd_log} "templates:widgets:sources …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-sources
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/sources/templates/* ${dir_build}/templates/widget-sources/
|
||||
|
||||
.PHONY: templates-widgets-calendar_edit
|
||||
templates-widgets-calendar_edit: \
|
||||
$(wildcard ${dir_source}/widgets/calendar_edit/templates/*)
|
||||
@ ${cmd_log} "templates:widget:calendar_edit …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-calendar_edit
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/calendar_edit/templates/* ${dir_build}/templates/widget-calendar_edit/
|
||||
|
||||
.PHONY: templates-widgets-event_edit
|
||||
templates-widgets-event_edit: \
|
||||
$(wildcard ${dir_source}/widgets/event_edit/templates/*)
|
||||
@ ${cmd_log} "templates:widget:event_edit …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-event_edit
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/event_edit/templates/* ${dir_build}/templates/widget-event_edit/
|
||||
|
||||
.PHONY: templates-widgets-caldav
|
||||
templates-widgets-caldav: \
|
||||
$(wildcard ${dir_source}/widgets/caldav/templates/*)
|
||||
@ ${cmd_log} "templates:widget:caldav …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-caldav
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/caldav/templates/* ${dir_build}/templates/widget-caldav/
|
||||
|
||||
.PHONY: templates-widgets-listview
|
||||
templates-widgets-listview: \
|
||||
$(wildcard ${dir_source}/widgets/listview/templates/*)
|
||||
@ ${cmd_log} "templates:widget:listview …"
|
||||
@ ${cmd_log} "templates:widgets:listview …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-listview
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/listview/templates/* ${dir_build}/templates/widget-listview/
|
||||
|
||||
.PHONY: templates-widgets-weekview
|
||||
templates-widgets-weekview: \
|
||||
$(wildcard ${dir_source}/widgets/weekview/templates/*)
|
||||
@ ${cmd_log} "templates:widget:weekview …"
|
||||
@ ${cmd_log} "templates:widgets:weekview …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-weekview
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/weekview/templates/* ${dir_build}/templates/widget-weekview/
|
||||
|
||||
.PHONY: templates-widgets-overview
|
||||
templates-widgets-overview: \
|
||||
$(wildcard ${dir_source}/widgets/overview/templates/*)
|
||||
@ ${cmd_log} "templates:widget:overview …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-overview
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/overview/templates/* ${dir_build}/templates/widget-overview/
|
||||
.PHONY: templates-pages-caldav
|
||||
templates-pages-caldav: \
|
||||
$(wildcard ${dir_source}/pages/caldav/templates/*)
|
||||
@ ${cmd_log} "templates:caldav …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/caldav
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/caldav/templates/* ${dir_build}/templates/caldav/
|
||||
|
||||
.PHONY: templates-widgets-mode_switcher
|
||||
templates-widgets-mode_switcher: \
|
||||
$(wildcard ${dir_source}/widgets/mode_switcher/templates/*)
|
||||
@ ${cmd_log} "templates:widget:mode_switcher …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/widget-mode_switcher
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/mode_switcher/templates/* ${dir_build}/templates/widget-mode_switcher/
|
||||
.PHONY: templates-pages-calendar_add
|
||||
templates-pages-calendar_add: \
|
||||
$(wildcard ${dir_source}/pages/calendar_add/templates/*)
|
||||
@ ${cmd_log} "templates:calendar_add …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/calendar_add
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/calendar_add/templates/* ${dir_build}/templates/calendar_add/
|
||||
|
||||
.PHONY: templates-pages-calendar_edit
|
||||
templates-pages-calendar_edit: \
|
||||
$(wildcard ${dir_source}/pages/calendar_edit/templates/*)
|
||||
@ ${cmd_log} "templates:calendar_edit …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/calendar_edit
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/calendar_edit/templates/* ${dir_build}/templates/calendar_edit/
|
||||
|
||||
.PHONY: templates-pages-event_add
|
||||
templates-pages-event_add: \
|
||||
$(wildcard ${dir_source}/pages/event_add/templates/*)
|
||||
@ ${cmd_log} "templates:event_add …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/event_add
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/event_add/templates/* ${dir_build}/templates/event_add/
|
||||
|
||||
.PHONY: templates-pages-event_edit
|
||||
templates-pages-event_edit: \
|
||||
$(wildcard ${dir_source}/pages/event_edit/templates/*)
|
||||
@ ${cmd_log} "templates:event_edit …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/event_edit
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/event_edit/
|
||||
|
||||
.PHONY: templates-pages-overview
|
||||
templates-pages-overview: \
|
||||
$(wildcard ${dir_source}/pages/overview/templates/*)
|
||||
@ ${cmd_log} "templates:overview …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/overview
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/overview/templates/* ${dir_build}/templates/overview/
|
||||
|
||||
.PHONY: templates-pages-login
|
||||
templates-pages-login: \
|
||||
$(wildcard ${dir_source}/pages/login/templates/*)
|
||||
@ ${cmd_log} "templates:login …"
|
||||
@ ${cmd_mkdir} ${dir_build}/templates/login
|
||||
@ ${cmd_cp} -r -u -v ${dir_source}/pages/login/templates/* ${dir_build}/templates/login/
|
||||
|
||||
.PHONY: style
|
||||
style: ${dir_build}/style.css
|
||||
|
||||
${dir_build}/style.css: \
|
||||
$(wildcard ${dir_source}/style/*.css) \
|
||||
$(wildcard ${dir_source}/widgets/*/style.css)
|
||||
style: \
|
||||
$(wildcard ${dir_source}/style/*)
|
||||
@ ${cmd_log} "style …"
|
||||
@ ${cmd_mkdir} ${dir_build}
|
||||
@ ${cmd_cat} $^ > $@
|
||||
@ ${cmd_cat} ${dir_source}/style/* > ${dir_build}/style.css
|
||||
|
||||
.PHONY: logic
|
||||
logic: ${dir_build}/logic.js
|
||||
|
||||
${dir_temp}/logic-unlinked.js: \
|
||||
${dir_lib}/plankton/plankton.d.ts \
|
||||
${dir_source}/resources/conf.ts \
|
||||
${dir_source}/resources/backend.ts \
|
||||
${dir_source}/base.ts \
|
||||
${dir_source}/types.ts \
|
||||
${dir_source}/model.ts \
|
||||
${dir_source}/overlay.ts \
|
||||
${dir_source}/helpers.ts \
|
||||
$(wildcard ${dir_source}/widgets/*/logic.ts) \
|
||||
${dir_source}/main.ts
|
||||
${dir_source}/logic/helpers.ts \
|
||||
${dir_source}/logic/widget.ts \
|
||||
${dir_source}/logic/conf.ts \
|
||||
${dir_source}/logic/types.ts \
|
||||
${dir_source}/logic/backend.ts \
|
||||
${dir_source}/widgets/sources/logic.ts \
|
||||
${dir_source}/widgets/listview/logic.ts \
|
||||
${dir_source}/widgets/weekview/logic.ts \
|
||||
${dir_source}/pages/login/logic.ts \
|
||||
${dir_source}/pages/logout/logic.ts \
|
||||
${dir_source}/pages/caldav/logic.ts \
|
||||
${dir_source}/pages/oidc_finish/logic.ts \
|
||||
${dir_source}/pages/calendar_add/logic.ts \
|
||||
${dir_source}/pages/calendar_edit/logic.ts \
|
||||
${dir_source}/pages/event_add/logic.ts \
|
||||
${dir_source}/pages/event_edit/logic.ts \
|
||||
${dir_source}/pages/overview/logic.ts \
|
||||
${dir_source}/logic/main.ts
|
||||
@ ${cmd_log} "logic | compile …"
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_tsc} --lib dom,es2020 $^ --outFile $@ # --strict
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@ modules="${modules} storage"
|
|||
modules="${modules} file"
|
||||
modules="${modules} json"
|
||||
modules="${modules} string"
|
||||
modules="${modules} random"
|
||||
modules="${modules} map"
|
||||
modules="${modules} set"
|
||||
modules="${modules} cache"
|
||||
modules="${modules} color"
|
||||
# modules="${modules} xml"
|
||||
modules="${modules} map"
|
||||
|
|
@ -25,7 +22,6 @@ modules="${modules} url"
|
|||
modules="${modules} pit"
|
||||
modules="${modules} www_form"
|
||||
modules="${modules} translate"
|
||||
modules="${modules} zoo-widget"
|
||||
modules="${modules} zoo-page"
|
||||
modules="${modules} zoo-form"
|
||||
modules="${modules} zoo-input"
|
||||
|
|
|
|||
Loading…
Reference in a new issue