Compare commits

..

No commits in common. "57ce184761e55fc64b7dec4766313c72629a5988" and "1c8d3d0725fabdc6d6f9c29677ccd944c7af72b4" have entirely different histories.

43 changed files with 635 additions and 958 deletions

View file

@ -7,7 +7,7 @@
"path": "" "path": ""
}, },
"misc": { "misc": {
"oidc_redirect_uri_template": "http://localhost:8888/?action=oidc_finish&session_key={{session_key}}", "oidc_redirect_uri_template": "http://localhost:8888/#oidc_finish,session_key={{session_key}}",
"use_central_europe_specific_datetime_inputs": true "use_central_europe_specific_datetime_inputs": true
} }
} }

View file

@ -106,19 +106,8 @@ namespace _dali
{ {
await _dali.backend.set_session_key(session_key); await _dali.backend.set_session_key(session_key);
const status = await _dali.backend.status(); const status = await _dali.backend.status();
if (! status.logged_in) await _dali.notify_login(status.name);
{ return Promise.resolve<void>(undefined);
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);
}
} }

View file

@ -27,7 +27,6 @@
"common.monthname.november": "Nov", "common.monthname.november": "Nov",
"common.monthname.december": "Dez", "common.monthname.december": "Dez",
"common.open": "öffnen", "common.open": "öffnen",
"common.close": "schließen",
"common.edit": "bearbeiten", "common.edit": "bearbeiten",
"common.show": "zeigen", "common.show": "zeigen",
"common.hide": "ausblenden", "common.hide": "ausblenden",
@ -79,20 +78,27 @@
"widget.login.internal.password": "Kennwort", "widget.login.internal.password": "Kennwort",
"widget.login.internal.do": "Anmelden", "widget.login.internal.do": "Anmelden",
"widget.login.oidc.via": "via {{title}}", "widget.login.oidc.via": "via {{title}}",
"widget.caldav.title": "CalDAV", "page.caldav.title": "CalDAV",
"widget.caldav.unavailable": "CalDAV nicht verfügbar", "page.caldav.unavailable": "CalDAV nicht verfügbar",
"widget.caldav.conf.title": "Zugangsdaten", "page.caldav.conf.title": "Zugangsdaten",
"widget.caldav.conf.address": "Adresse (URL)", "page.caldav.conf.address": "Adresse (URL)",
"widget.caldav.conf.username": "Nutzername", "page.caldav.conf.username": "Nutzername",
"widget.caldav.conf.password": "Kennwort", "page.caldav.conf.password": "Kennwort",
"widget.caldav.conf.setup_hints": "Einrichtungs-Hinweise", "page.caldav.conf.setup_hints": "Einrichtungs-Hinweise",
"widget.caldav.conf.token_unset": "es muss zunächst ein Token gesetzt werden", "page.caldav.conf.token_unset": "es muss zunächst ein Token gesetzt werden",
"widget.caldav.set_token.title": "Token setzen", "page.caldav.set_token.title": "Token setzen",
"widget.caldav.set_token.action.set": "setzen", "page.caldav.set_token.action.set": "setzen",
"widget.caldav.set_token.action.overwrite": "überschreiben", "page.caldav.set_token.action.overwrite": "überschreiben",
"widget.overview.title": "Übersicht", "page.calendar_add.title": "Kalendar anlegen",
"widget.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen", "page.calendar_add.actions.do": "anlegen",
"widget.overview.mode.week": "Wochen-Ansicht", "page.calendar_edit.title.regular": "Kalendar bearbeiten",
"widget.overview.mode.list": "Listen-Ansicht" "page.calendar_edit.title.read_only": "Kalendar-Details",
"page.event_add.title": "Termin anlegen",
"page.event_edit.title.regular": "Termin bearbeiten",
"page.event_edit.title.read_only": "Termin-Details",
"page.overview.title": "Übersicht",
"page.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen",
"page.overview.mode.week": "Wochen-Ansicht",
"page.overview.mode.list": "Listen-Ansicht"
} }
} }

View file

@ -27,7 +27,6 @@
"common.monthname.november": "nov", "common.monthname.november": "nov",
"common.monthname.december": "dec", "common.monthname.december": "dec",
"common.open": "open", "common.open": "open",
"common.close": "close",
"common.edit": "edit", "common.edit": "edit",
"common.show": "show", "common.show": "show",
"common.hide": "hide", "common.hide": "hide",
@ -79,20 +78,27 @@
"widget.login.internal.password": "password", "widget.login.internal.password": "password",
"widget.login.internal.do": "login", "widget.login.internal.do": "login",
"widget.login.oidc.via": "via {{title}}", "widget.login.oidc.via": "via {{title}}",
"widget.caldav.title": "CalDAV", "page.caldav.title": "CalDAV",
"widget.caldav.unavailable": "CalDAV not available", "page.caldav.unavailable": "CalDAV not available",
"widget.caldav.conf.title": "credentials", "page.caldav.conf.title": "credentials",
"widget.caldav.conf.address": "address (URL)", "page.caldav.conf.address": "address (URL)",
"widget.caldav.conf.username": "username", "page.caldav.conf.username": "username",
"widget.caldav.conf.password": "password", "page.caldav.conf.password": "password",
"widget.caldav.conf.setup_hints": "setup hints", "page.caldav.conf.setup_hints": "setup hints",
"widget.caldav.conf.token_unset": "a token has to be set", "page.caldav.conf.token_unset": "a token has to be set",
"widget.caldav.set_token.title": "set token", "page.caldav.set_token.title": "set token",
"widget.caldav.set_token.action.set": "set", "page.caldav.set_token.action.set": "set",
"widget.caldav.set_token.action.overwrite": "overwrite", "page.caldav.set_token.action.overwrite": "overwrite",
"widget.overview.title": "Overview", "page.calendar_add.title": "Add calendar",
"widget.overview.login_hint": "log in to view non-public events", "page.calendar_add.actions.do": "anlegen",
"widget.overview.mode.week": "week view", "page.event_add.title": "Add event",
"widget.overview.mode.list": "list view" "page.calendar_edit.title.regular": "Edit calendar",
"page.calendar_edit.title.read_only": "Calendar details",
"page.event_edit.title.regular": "Edit event",
"page.event_edit.title.read_only": "Event details",
"page.overview.title": "Overview",
"page.overview.login_hint": "log in to view non-public events",
"page.overview.mode.week": "week view",
"page.overview.mode.list": "list view"
} }
} }

View file

@ -350,23 +350,4 @@ namespace _dali.helpers
return lib_plankton.translate.get(keys[month-1]); 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});
}
}
} }

View file

@ -23,6 +23,24 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
namespace _dali namespace _dali
{ {
/**
*/
function nav_groups(
logged_in : boolean
)
: Array<string>
{
return (
logged_in
?
["logged_in"]
:
["logged_out"]
);
}
/** /**
*/ */
export async function main( export async function main(
@ -34,7 +52,7 @@ namespace _dali
"conf.json" "conf.json"
); );
// init:logger // init
lib_plankton.log.set_main_logger( lib_plankton.log.set_main_logger(
[ [
{ {
@ -50,11 +68,6 @@ namespace _dali
}, },
] ]
); );
// init:overlay
{
await _dali.overlay.initialize();
_dali.helpers.loading(true);
}
// init:localization // init:localization
{ {
const order : Array<string> = ["deu", "eng"]; const order : Array<string> = ["deu", "eng"];
@ -63,11 +76,10 @@ namespace _dali
"verbosity": 1, "verbosity": 1,
"packages": await Promise.all( "packages": await Promise.all(
order.map( order.map(
code => ( async (code) => JSON.parse(
Promise.resolve(code) await lib_plankton.file.read(
.then<string>(code => Promise.resolve(lib_plankton.string.coin("data/localization/{{code}}.loc.json", {"code": code}))) "data/localization/" + code + ".loc.json"
.then<string>(lib_plankton.file.read) )
.then<any>(content => Promise.resolve(JSON.parse(content)))
) )
) )
), ),
@ -76,14 +88,11 @@ namespace _dali
} }
); );
} }
// init:backend
await _dali.backend.initialize( await _dali.backend.initialize(
_dali.conf.get()["backend"] _dali.conf.get()["backend"]
); );
// init:model
await _dali.model.initialize( await _dali.model.initialize(
); );
// init:page
lib_plankton.zoo_page.init( lib_plankton.zoo_page.init(
document.querySelector("main"), document.querySelector("main"),
{ {
@ -91,55 +100,69 @@ namespace _dali
"name": "overview", "name": "overview",
"parameters": {} "parameters": {}
}, },
/*
"nav_entries": [
],
*/
"nav_initial_groups": [],
} }
); );
// init:menu // menu widget
{ {
const widget_menu : _dali.widgets.class_widget_menu = new _dali.widgets.class_widget_menu( const widget_menu : _dali.widgets.menu.class_widget_menu = new _dali.widgets.menu.class_widget_menu(
[ [
{ {
"label": lib_plankton.translate.get("common.login"), "label": lib_plankton.translate.get("common.login"),
"groups": ["logged_out"], "groups": ["logged_out"],
"action": async () => { "action": () => {
_dali.helpers.loading(true); const widget_login = new _dali.widgets.login.class_widget_login(
const widget : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.class_widget_login(
{ {
"action_cancel": () => { "action_cancel": () => {
_dali.overlay.clear(); _dali.overlay.clear();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
}, },
"action_success": async () => { "action_success": async () => {
_dali.helpers.loading(true);
const status = await _dali.backend.status(); const status = await _dali.backend.status();
_dali.notify_login(status.name); _dali.notify_login(status.name);
// _dali.overlay.clear(); _dali.overlay.clear();
_dali.helpers.loading(false); _dali.overlay.toggle({"mode": false});
}, },
} }
); );
await widget.load(_dali.overlay.get_content_element()); _dali.overlay.clear();
// _dali.helpers.loading(false);
_dali.overlay.toggle({"mode": true}); _dali.overlay.toggle({"mode": true});
widget_login.load(_dali.overlay.get_content_element());
}, },
}, },
{ {
"label": lib_plankton.translate.get("widget.caldav.title"), "label": lib_plankton.translate.get("page.overview.title"),
"groups": ["logged_out", "logged_in"],
"action": () => {
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
},
},
{
"label": lib_plankton.translate.get("page.caldav.title"),
"groups": ["logged_in"], "groups": ["logged_in"],
"action": async () => { "action": () => {
_dali.helpers.loading(true); lib_plankton.zoo_page.set(
const widget : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.class_widget_caldav(); {
await widget.load(_dali.overlay.get_content_element()); "name": "caldav",
// _dali.helpers.loading(false); "parameters": {}
_dali.overlay.toggle({"mode": true}); }
);
}, },
}, },
{ {
"label": lib_plankton.translate.get("common.logout"), "label": lib_plankton.translate.get("common.logout"),
"groups": ["logged_in"], "groups": ["logged_in"],
"action": async () => { "action": () => {
_dali.helpers.loading(true); _dali.logout();
await _dali.logout();
_dali.helpers.loading(false);
}, },
}, },
] ]
@ -158,36 +181,9 @@ namespace _dali
} }
); );
} }
await _dali.overlay.initialize();
// process actions // check if logged_in
{
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(); const status = await _dali.backend.status();
lib_plankton.log.info( lib_plankton.log.info(
@ -204,15 +200,7 @@ namespace _dali
} }
} }
// load overview lib_plankton.zoo_page.start();
{
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); return Promise.resolve<void>(undefined);
} }

View file

@ -24,8 +24,7 @@ namespace _dali.overlay
/** /**
*/ */
function get_container_element( function get_container_element(
) ) : HTMLElement
: HTMLElement
{ {
return document.querySelector("#overlay"); return document.querySelector("#overlay");
} }
@ -34,8 +33,7 @@ namespace _dali.overlay
/** /**
*/ */
export function get_content_element( export function get_content_element(
) ) : HTMLElement
: HTMLElement
{ {
return document.querySelector("#overlay_content"); return document.querySelector("#overlay_content");
} }
@ -44,8 +42,7 @@ namespace _dali.overlay
/** /**
*/ */
export function clear( export function clear(
) ) : void
: void
{ {
get_content_element().innerHTML = ""; get_content_element().innerHTML = "";
} }
@ -64,8 +61,7 @@ namespace _dali.overlay
= =
{ {
} }
) ) : void
: void
{ {
get_container_element().classList.toggle("overlay_active", mode ?? undefined); get_container_element().classList.toggle("overlay_active", mode ?? undefined);
} }
@ -74,8 +70,7 @@ namespace _dali.overlay
/** /**
*/ */
export function initialize( export function initialize(
) ) : Promise<void>
: Promise<void>
{ {
clear(); clear();
const container_element : HTMLElement = get_container_element(); const container_element : HTMLElement = get_container_element();

View file

@ -18,80 +18,65 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.pages
{ {
/** /**
*/ */
export class class_widget_caldav lib_plankton.zoo_page.register(
{ "caldav",
async (parameters, target_element) => {
/**
*/
public constructor(
)
{
}
/**
*/
public async load(
target_element : HTMLElement
)
: Promise<void>
{
target_element.innerHTML = ""; target_element.innerHTML = "";
const conf = await _dali.backend.user_dav_conf(); const conf = await _dali.backend.user_dav_conf();
target_element.innerHTML = await _dali.helpers.template_coin( target_element.innerHTML = await _dali.helpers.template_coin(
"widget-caldav", "caldav",
"main", "main",
{ {
"title": lib_plankton.translate.get("widget.caldav.title"), "label": lib_plankton.translate.get("page.caldav.title"),
"content": ( "content": (
(conf === null) (conf === null)
? ?
await _dali.helpers.template_coin( await _dali.helpers.template_coin(
"widget-caldav", "caldav",
"unavailable", "unavailable",
{ {
"text": lib_plankton.translate.get("widget.caldav.unavailable"), "text": lib_plankton.translate.get("page.caldav.unavailable"),
} }
) )
: :
await _dali.helpers.template_coin( await _dali.helpers.template_coin(
"widget-caldav", "caldav",
"available", "available",
{ {
"conf_title": lib_plankton.translate.get("widget.caldav.conf.title"), "conf_title": lib_plankton.translate.get("page.caldav.conf.title"),
"conf_content": ( "conf_content": (
(conf.password === null) (conf.password === null)
? ?
await _dali.helpers.template_coin( await _dali.helpers.template_coin(
"widget-caldav", "caldav",
"conf-token_unset", "conf-token_unset",
{ {
"text": lib_plankton.translate.get("widget.caldav.conf.token_unset") "text": lib_plankton.translate.get("page.caldav.conf.token_unset")
} }
) )
: :
await _dali.helpers.template_coin( await _dali.helpers.template_coin(
"widget-caldav", "caldav",
"conf-token_set", "conf-token_set",
{ {
"address_label": lib_plankton.translate.get("widget.caldav.conf.address"), "address_label": lib_plankton.translate.get("page.caldav.conf.address"),
"address_value": conf.address, "address_value": conf.address,
"username_label": lib_plankton.translate.get("widget.caldav.conf.username"), "username_label": lib_plankton.translate.get("page.caldav.conf.username"),
"username_value": conf.username, "username_value": conf.username,
"password_label": lib_plankton.translate.get("widget.caldav.conf.password"), "password_label": lib_plankton.translate.get("page.caldav.conf.password"),
"password_value": conf.password, "password_value": conf.password,
"setup_hints_label": lib_plankton.translate.get("widget.caldav.conf.setup_hints"), "setup_hints_label": lib_plankton.translate.get("page.caldav.conf.setup_hints"),
"setup_hint_entries": ( "setup_hint_entries": (
await lib_plankton.call.promise_condense<string, unknown>( await lib_plankton.call.promise_condense<string, unknown>(
conf.setup_hints conf.setup_hints
.map( .map(
entry => () => _dali.helpers.template_coin( entry => () => _dali.helpers.template_coin(
"widget-caldav", "caldav",
"conf-setup_hint_entry", "conf-setup_hint_entry",
{ {
"text": entry.label, "text": entry.label,
@ -116,45 +101,31 @@ namespace _dali.widgets
} }
) )
), ),
"set_token_title": lib_plankton.translate.get("widget.caldav.set_token.title"), "set_token_title": lib_plankton.translate.get("page.caldav.set_token.title"),
"set_token_action": ( "set_token_action": (
(conf.password === null) (conf.password === null)
? ?
lib_plankton.translate.get("widget.caldav.set_token.action.set") lib_plankton.translate.get("page.caldav.set_token.action.set")
: :
lib_plankton.translate.get("widget.caldav.set_token.action.overwrite") lib_plankton.translate.get("page.caldav.set_token.action.overwrite")
), ),
} }
) )
), )
"close": lib_plankton.translate.get("common.close"),
} }
); );
// logic
/**
* logic: set token
*/
{ {
// set token if (conf !== null)
{ {
if (conf === null) document.querySelector("#caldav-set_token > button").addEventListener(
{
// 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", "click",
() => { async () => {
_dali.overlay.toggle({"mode": false}); await _dali.backend.user_dav_token();
lib_plankton.zoo_page.reload();
} }
); );
} }
@ -162,8 +133,7 @@ namespace _dali.widgets
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} }
);
}
} }

View file

@ -1,9 +1,9 @@
.widget-caldav-conf-section .caldav-conf-section
{ {
margin-bottom: 16px; margin-bottom: 16px;
} }
.widget-caldav-conf-section-label .caldav-conf-section-label
{ {
margin-left: 16px; margin-left: 16px;
display: block; display: block;
@ -11,12 +11,12 @@
text-transform: capitalize; text-transform: capitalize;
} }
.widget-caldav-conf-section-value .caldav-conf-section-value
{ {
margin-left: 32px; margin-left: 32px;
} }
.widget-caldav-conf-section-value-regular .caldav-conf-section-value-regular
{ {
font-family: monospace; font-family: monospace;
} }

View file

@ -1,8 +1,8 @@
<div class="widget-caldav-conf"> <div id="caldav-conf">
<h3>{{conf_title}}</h3> <h3>{{conf_title}}</h3>
{{conf_content}} {{conf_content}}
</div> </div>
<div class="widget-caldav-set_token"> <div id="caldav-set_token">
<h3>{{set_token_title}}</h3> <h3>{{set_token_title}}</h3>
<button>{{set_token_action}}</button> <button>{{set_token_action}}</button>
</div> </div>

View file

@ -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}} <a target="_blank" href="{{href}}">{{text}}</a>{{remark}}
</li> </li>

View 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>

View file

@ -0,0 +1,4 @@
<div id="caldav-conf-info">
({{text}})
</div>

View file

@ -0,0 +1,6 @@
<div id="caldav">
<h2>{{label}}</h2>
<div id="caldav-content">
{{content}}
</div>
</div>

View file

@ -0,0 +1,3 @@
<div id="caldav-info">
{{text}}
</div>

View file

@ -0,0 +1,41 @@
/*
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.pages
{
/**
*/
lib_plankton.zoo_page.register(
"oidc_finish",
async (parameters, target_element) => {
target_element.innerHTML = "";
await _dali.oidc_finish(parameters["session_key"]);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -18,98 +18,120 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.pages.overview
{ {
/** /**
*/ */
type type_action_create_calendar = ( lib_plankton.zoo_page.register(
( "overview",
) async (parameters, target_element) => {
=> // params
Promise<void> const view_mode : _dali.enum_view_mode = _dali.helpers.view_mode_determine(parameters["mode"] ?? "auto");
); const view_kind : _dali.enum_view_kind = _dali.helpers.view_kind_determine(parameters["kind"] ?? "auto");
// exec
/** /**
*/ */
type type_action_edit_calendar = ( async function get_available_calendars(
( )
type_calendar_object_reduced_with_id : Promise<
) Array<
=> _dali.type_calendar_object_reduced_with_id
Promise<void> >
); >
{
return (
/** (await _dali.model.calendar_list())
*/ /*
type type_action_create_event = ( .filter(
( (entry) => (
stuff ?: { (entry.access_level === _dali.enum_access_level.edit)
date ?: lib_plankton.pit.type_date; ||
(entry.access_level === _dali.enum_access_level.admin)
)
)
*/
);
} }
)
=>
Promise<void>
);
/**
* @todo add return type
*/
async function 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();
}
/** /**
*/ * @todo update listview
type type_action_edit_event = ( */
( async function update_sources_and_entries(
event_key : _dali.type_event_key {
) "priviliged": priviliged = null,
=> }
Promise<void> :
); {
priviliged ?: (null | boolean);
}
=
{
}
)
: Promise<void>
{
await widget_sources.update({"priviliged": priviliged});
await widget_multiview.update_entries();
}
/**
* @todo use priviliged?
* @todo update listview
*/
async function update_entries(
{
"priviliged": priviliged = null,
}
:
{
priviliged ?: (null | boolean);
}
=
{
}
)
: Promise<void>
{
await widget_multiview.update_entries();
}
/** /**
*/ */
export class class_widget_overview async function action_create_calendar(
implements lib_plankton.zoo_widget.interface_widget )
{ : Promise<void>
{
/** const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit(
*/
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.group_list(),
await _dali.model.user_list(), await _dali.model.user_list(),
{ {
@ -157,7 +179,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_sources_and_entries(); update_sources_and_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
) )
@ -175,10 +197,15 @@ namespace _dali.widgets
_dali.overlay.clear(); _dali.overlay.clear();
_dali.overlay.toggle({"mode": true}); _dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element()); await widget.load(_dali.overlay.get_content_element());
}; }
this.action_edit_calendar = async (
calendar_object_reduced_with_id /**
) => { */
async function action_edit_calendar(
calendar_object_reduced_with_id : type_calendar_object_reduced_with_id
)
: Promise<void>
{
const read_only : boolean = (() => { const read_only : boolean = (() => {
switch (calendar_object_reduced_with_id.access_level) switch (calendar_object_reduced_with_id.access_level)
{ {
@ -215,7 +242,7 @@ namespace _dali.widgets
const calendar_object : _dali.type_calendar_object = await _dali.model.calendar_get( const calendar_object : _dali.type_calendar_object = await _dali.model.calendar_get(
calendar_id calendar_id
); );
const widget = new _dali.widgets.class_widget_calendar_edit( const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit(
await _dali.model.group_list(), await _dali.model.group_list(),
await _dali.model.user_list(), await _dali.model.user_list(),
calendar_object, calendar_object,
@ -231,7 +258,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_sources_and_entries(); update_sources_and_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
); );
@ -242,7 +269,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_sources_and_entries(); update_sources_and_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
); );
@ -254,10 +281,11 @@ namespace _dali.widgets
await widget.load(_dali.overlay.get_content_element()); await widget.load(_dali.overlay.get_content_element());
} }
} }
/** /**
* @todo unterschiedliches Verhalten bei Anmeldung? * @todo unterschiedliches Verhalten bei Anmeldung?
*/ */
this.action_create_event = async ( async function action_create_event(
{ {
"date": date = lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date, "date": date = lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date,
} }
@ -268,15 +296,17 @@ namespace _dali.widgets
= =
{ {
} }
) => { )
: Promise<void>
{
if (! _dali.is_logged_in()) if (! _dali.is_logged_in())
{ {
// do nothing // do nothing
} }
else else
{ {
const widget = new _dali.widgets.class_widget_event_edit( const widget = new _dali.widgets.event_edit.class_widget_event_edit(
(await this.get_available_calendars()), (await get_available_calendars()),
{ {
"calendar_id": null, "calendar_id": null,
"event_name": "", "event_name": "",
@ -329,7 +359,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_entries(); update_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
) )
@ -346,11 +376,15 @@ namespace _dali.widgets
await widget.load(_dali.overlay.get_content_element()); await widget.load(_dali.overlay.get_content_element());
} }
} }
/** /**
*/ */
this.action_edit_event = async ( async function action_edit_event
event_key (
) => { event_key : _dali.type_event_key
)
: Promise<void>
{
const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key); const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key);
const read_only : boolean = (() => { const read_only : boolean = (() => {
switch (event_object_extended.access_level) switch (event_object_extended.access_level)
@ -373,8 +407,8 @@ namespace _dali.widgets
} }
} }
}) (); }) ();
const widget = new _dali.widgets.class_widget_event_edit( const widget = new _dali.widgets.event_edit.class_widget_event_edit(
(await this.get_available_calendars()), (await get_available_calendars()),
{ {
"calendar_id": event_object_extended.calendar_id, "calendar_id": event_object_extended.calendar_id,
"event_name": event_object_extended.event_object.name, "event_name": event_object_extended.event_object.name,
@ -403,7 +437,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_entries(); update_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
) )
@ -422,7 +456,7 @@ namespace _dali.widgets
) )
.then( .then(
() => { () => {
this.update_entries(); update_entries();
_dali.overlay.toggle({"mode": false}); _dali.overlay.toggle({"mode": false});
} }
) )
@ -437,212 +471,98 @@ namespace _dali.widgets
}, },
} }
); );
_dali.overlay.clear(); _dali.overlay.clear();
_dali.overlay.toggle({"mode": true}); _dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element()); await widget.load(_dali.overlay.get_content_element());
} }
}
const widget_sources : _dali.widgets.sources.class_widget_sources = (
/** new _dali.widgets.sources.class_widget_sources(
*/
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, _dali.model.calendar_list,
{ {
"initial_priviliged": _dali.is_logged_in(), "initial_priviliged": _dali.is_logged_in(),
"action_add": this.action_create_calendar, "action_add": action_create_calendar,
"action_select": this.action_edit_calendar, "action_select": (entry) => action_edit_calendar(entry),
"action_toggle": (entry, mode) => { "action_toggle": (entry, mode) => {
this.widget_multiview.toggle_calendar_visibilty(entry.id, {"mode": mode}); widget_multiview.toggle_calendar_visibilty(entry.id, {"mode": mode});
}, },
} }
) )
); );
this.widget_multiview = ( const widget_multiview : _dali.widgets.multiview.class_widget_multiview = (
new _dali.widgets.class_widget_multiview( new _dali.widgets.multiview.class_widget_multiview(
this.get_entries, get_entries,
{ {
"initial_view_mode": view_mode, "initial_view_mode": view_mode,
"weekview_initial_vertical": (view_kind === _dali.enum_view_kind.touch), "weekview_initial_vertical": (view_kind === _dali.enum_view_kind.touch),
"action_create_event": this.action_create_event, "action_create_event": action_create_event,
"action_edit_event": this.action_edit_event, "action_edit_event": action_edit_event,
} }
) )
); );
target_element.innerHTML = await _dali.helpers.template_coin( target_element.innerHTML = await _dali.helpers.template_coin(
"widget-overview", "overview",
"main", "main",
{ {
} }
); );
// head switch (view_kind)
{ {
// hint case _dali.enum_view_kind.regular:
{ {
const dom_hint = target_element.querySelector(".widget-overview-hint"); const widget_slider = new lib_plankton.zoo_widget.class_slider(
dom_hint.textContent = lib_plankton.translate.get("widget.overview.login_hint"); [
dom_hint.classList.toggle("widget-overview-hint-hidden", _dali.is_logged_in()); new lib_plankton.zoo_widget.class_bunch(
[
widget_sources,
widget_multiview,
]
),
],
{
"threshold": 100,
"initial_index": 1,
}
);
await widget_slider.load(target_element.querySelector("#overview-body"));
break;
}
case _dali.enum_view_kind.touch:
{
const widget_slider = new lib_plankton.zoo_widget.class_slider(
[
widget_sources,
widget_multiview,
],
{
"threshold": 100,
"initial_index": 2,
}
);
await widget_slider.load(target_element.querySelector("#overview-body"));
break;
} }
} }
// body
// hint
{ {
let widget_slider : lib_plankton.zoo_widget.interface_widget; const dom_hint = target_element.querySelector("#overview-hint");
switch (view_kind) dom_hint.textContent = lib_plankton.translate.get("page.overview.login_hint");
{ dom_hint.classList.toggle("overview-hint-hidden", _dali.is_logged_in());
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( _dali.model.listen_reset(
async (priviliged) => { async (priviliged) => {
this.update_sources_and_entries({"priviliged": priviliged}); update_sources_and_entries({"priviliged": priviliged});
target_element.querySelector(".widget-overview-hint").classList.toggle("widget-overview-hint-hidden", priviliged); target_element.querySelector("#overview-hint").classList.toggle("overview-hint-hidden", priviliged);
} }
); );
return Promise.resolve<void>(undefined); return Promise.resolve<void>(undefined);
} },
);
}
} }

View file

@ -1,57 +1,57 @@
.widget-overview-head #overview-head
{ {
padding-bottom: 12px; padding-bottom: 12px;
margin-bottom: 12px; margin-bottom: 12px;
border-bottom: 1px solid; border-bottom: 1px solid;
} }
.widget-overview-hint #overview-hint
{ {
text-align: center; text-align: center;
font-weight: bold; font-weight: bold;
} }
.widget-overview-hint.widget-overview-hint-hidden #overview-hint.overview-hint-hidden
{ {
display: none; display: none;
} }
.widget-overview-body #overview-body
{ {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.widget-overview-pane-left #overview-pane-left
{ {
flex-basis: 12.5%; flex-basis: 12.5%;
flex-grow: 0; flex-grow: 0;
flex-shrink: 1; flex-shrink: 1;
} }
.widget-overview-pane-right #overview-pane-right
{ {
flex-basis: 87.5%; flex-basis: 87.5%;
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
} }
.widget-overview-body .widget-slider-slide .widget-bunch #overview-body .widget-slider-slide .widget-bunch
{ {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.widget-overview-body .widget-slider-slide .widget-bunch-element:nth-child(1) #overview-body .widget-slider-slide .widget-bunch-element:nth-child(1)
{ {
flex-grow: 0; flex-grow: 0;
flex-shrink: 1; flex-shrink: 1;
flex-basis: 12.5%; flex-basis: 12.5%;
} }
.widget-overview-body .widget-slider-slide .widget-bunch-element:nth-child(2) #overview-body .widget-slider-slide .widget-bunch-element:nth-child(2)
{ {
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;

View file

@ -0,0 +1,8 @@
<div id="overview">
<div id="overview-head">
<div id="overview-hint">
</div>
</div>
<div id="overview-body">
</div>
</div>

View file

@ -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>

View file

@ -1,4 +0,0 @@
<div class="widget-caldav-conf-info">
({{text}})
</div>

View file

@ -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>

View file

@ -1,3 +0,0 @@
<div class="widget-caldav-info">
{{text}}
</div>

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.calendar_edit
{ {
/** /**

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.event_edit
{ {
/** /**

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.listview
{ {
/** /**

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.login
{ {
/** /**
@ -73,7 +73,7 @@ namespace _dali.widgets
* [implementation] * [implementation]
*/ */
public async load( public async load(
target_element : HTMLElement target_element : Element
) )
: Promise<void> : Promise<void>
{ {
@ -86,36 +86,125 @@ namespace _dali.widgets
{ {
case "internal": case "internal":
{ {
const sub_widget : lib_plankton.zoo_widget.interface_widget = ( target_element.innerHTML = await _dali.helpers.template_coin(
new class_widget_login_internal( "widget-login",
preparation.data, "default",
{ {
"initial_name": this.initial_name, }
"action_cancel": this.action_cancel, );
"action_success": this.action_success, 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();
}
}
]
)
) )
); );
await sub_widget.load(target_element); await form.setup(document.querySelector(".widget-login"));
await form.input_write(
{
"name": this.initial_name,
"password": "",
}
);
break; break;
} }
case "oidc": case "oidc":
{ {
const sub_widget : lib_plankton.zoo_widget.interface_widget = ( // link
new class_widget_login_oidc( {
preparation.data, let element_a : HTMLElement = document.createElement("a");;
element_a.textContent = lib_plankton.string.coin(
lib_plankton.translate.get("widget.login.oidc.via"),
{ {
"action_cancel": this.action_cancel, "title": preparation.data.label,
"action_success": this.action_success,
} }
) );
); element_a.setAttribute("href", preparation.data.url);
await sub_widget.load(target_element); target_element.appendChild(element_a);
}
{
let dom_br : HTMLElement = document.createElement("br");
target_element.appendChild(dom_br);
}
{
let dom_br : HTMLElement = document.createElement("br");
target_element.appendChild(dom_br);
}
// cancel
{
let dom_cancel : HTMLElement = document.createElement("button");
dom_cancel.textContent = lib_plankton.translate.get("common.cancel");
dom_cancel.addEventListener(
"click",
() => {
this.action_cancel();
}
);
target_element.appendChild(dom_cancel);
}
break; break;
} }
default: default:
{ {
throw (new Error("unhandled login kind: " + preparation.kind)); // todo
break; break;
} }
} }

View file

@ -0,0 +1,2 @@
<div class="widget-login">
</div>

View file

@ -1,164 +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": "",
}
);
}
}
}

View file

@ -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();
}
);
}
}
}
}

View file

@ -1,5 +0,0 @@
.widget-login_oidc-cancel
{
display: block;
margin-top: 32px;
}

View file

@ -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>

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.menu
{ {
/** /**

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.mode_switcher
{ {
/** /**

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.multiview
{ {
/** /**
@ -96,17 +96,17 @@ namespace _dali.widgets
/** /**
*/ */
private widget_mode_switcher : _dali.widgets.class_widget_mode_switcher; private widget_mode_switcher : _dali.widgets.mode_switcher.class_widget_mode_switcher;
/** /**
*/ */
private widget_weekview : _dali.widgets.class_widget_weekview; private widget_weekview : _dali.widgets.weekview.class_widget_weekview;
/** /**
*/ */
private widget_listview : _dali.widgets.class_widget_listview; private widget_listview : _dali.widgets.listview.class_widget_listview;
/** /**
@ -205,21 +205,15 @@ namespace _dali.widgets
// mode switcher // mode switcher
{ {
this.widget_mode_switcher = ( this.widget_mode_switcher = (
new _dali.widgets.class_widget_mode_switcher( new _dali.widgets.mode_switcher.class_widget_mode_switcher(
[ [
{ {
"mode": _dali.enum_view_mode.week, "mode": _dali.enum_view_mode.week,
/** "label": lib_plankton.translate.get("page.overview.mode.week"),
* @todo as dependency
*/
"label": lib_plankton.translate.get("widget.overview.mode.week"),
}, },
{ {
"mode": _dali.enum_view_mode.list, "mode": _dali.enum_view_mode.list,
/** "label": lib_plankton.translate.get("page.overview.mode.list"),
* @todo as dependency
*/
"label": lib_plankton.translate.get("widget.overview.mode.list"),
}, },
], ],
{ {
@ -238,7 +232,7 @@ namespace _dali.widgets
// weekview // weekview
{ {
this.widget_weekview = ( this.widget_weekview = (
new _dali.widgets.class_widget_weekview( new _dali.widgets.weekview.class_widget_weekview(
this.get_entries, this.get_entries,
{ {
"action_select_event": (event_key) => this.action_edit_event(event_key), "action_select_event": (event_key) => this.action_edit_event(event_key),
@ -255,7 +249,7 @@ namespace _dali.widgets
// listview // listview
{ {
this.widget_listview = ( this.widget_listview = (
new _dali.widgets.class_widget_listview( new _dali.widgets.listview.class_widget_listview(
this.get_entries, this.get_entries,
{ {
"action_select": (event_key) => this.action_edit_event(event_key), "action_select": (event_key) => this.action_edit_event(event_key),

View file

@ -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>

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.sources
{ {
/** /**

View file

@ -100,7 +100,7 @@ namespace _dali.widgets
} }
); );
const dom_input : HTMLInputElement = (dom_dummy.querySelector(".widget-special_number_input-input") as HTMLInputElement); const dom_input : HTMLInputElement = (dom_dummy.querySelector(".widget-special_number_input-input > input") as HTMLInputElement);
// listeners // listeners
{ {

View file

@ -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;
}

View file

@ -1,8 +1,8 @@
<div class="widget-special_number_input"> <div class="widget-special_number_input">
<label class="widget-special_number_input-label">{{label}}</label> <label class="widget-special_number_input-label">{{label}}</label>
<div class="widget-special_number_input-controls"> <div class="widget-special_number_input-input">
<div class="widget-special_number_input-button widget-special_number_input-prev">&#x25C2;</div> <button class="widget-special_number_input-prev">&#x25C2;</button>
<input type="text" class="widget-special_number_input-input" pattern="-?[0-9]+"/> <input type="text" pattern="-?[0-9]+"/>
<div class="widget-special_number_input-button widget-special_number_input-next">&#x25B8;</div> <button class="widget-special_number_input-next">&#x25B8;</button>
</div> </div>
</div> </div>

View file

@ -18,7 +18,7 @@ along with »dali«. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace _dali.widgets namespace _dali.widgets.weekview
{ {
/** /**
@ -192,8 +192,7 @@ namespace _dali.widgets
*/ */
private static entry_hash( private static entry_hash(
entry : _dali.type_event_object_extended entry : _dali.type_event_object_extended
) ) : string
: string
{ {
return lib_plankton.call.convey( return lib_plankton.call.convey(
{ {
@ -215,8 +214,7 @@ namespace _dali.widgets
private static event_generate_tooltip( private static event_generate_tooltip(
calendar_name : string, calendar_name : string,
event_object : _dali.type_event_object event_object : _dali.type_event_object
) ) : string
: string
{ {
return ( return (
lib_plankton.string.coin( lib_plankton.string.coin(
@ -362,8 +360,7 @@ namespace _dali.widgets
*/ */
private async entry_insert( private async entry_insert(
entry : _dali.type_event_object_extended entry : _dali.type_event_object_extended
) ) : Promise<(null | HTMLElement)>
: Promise<(null | HTMLElement)>
{ {
const selector : string = lib_plankton.string.coin( const selector : string = lib_plankton.string.coin(
".weekview-cell[rel=\"{{rel}}\"] > .weekview-events", ".weekview-cell[rel=\"{{rel}}\"] > .weekview-events",
@ -426,8 +423,7 @@ namespace _dali.widgets
*/ */
private async entry_add( private async entry_add(
entry : _dali.type_event_object_extended entry : _dali.type_event_object_extended
) ) : Promise<void>
: Promise<void>
{ {
const dom_entry : (null | HTMLElement) = await this.entry_insert(entry); const dom_entry : (null | HTMLElement) = await this.entry_insert(entry);
if (dom_entry === null) if (dom_entry === null)
@ -452,8 +448,7 @@ namespace _dali.widgets
private async entry_update( private async entry_update(
key : _dali.type_event_key, key : _dali.type_event_key,
entry : _dali.type_event_object_extended entry : _dali.type_event_object_extended
) ) : Promise<void>
: Promise<void>
{ {
if (! this.event_map.has(key)) if (! this.event_map.has(key))
{ {
@ -509,8 +504,7 @@ namespace _dali.widgets
*/ */
private async entry_remove( private async entry_remove(
key : _dali.type_event_key key : _dali.type_event_key
) ) : Promise<void>
: Promise<void>
{ {
if (! this.event_map.has(key)) if (! this.event_map.has(key))
{ {
@ -539,8 +533,7 @@ namespace _dali.widgets
/** /**
*/ */
public async update_entries( public async update_entries(
) ) : Promise<void>
: Promise<void>
{ {
const entries : Array<_dali.type_event_object_extended> = await this.get_entries_wrapped( const entries : Array<_dali.type_event_object_extended> = await this.get_entries_wrapped(
); );
@ -581,8 +574,7 @@ namespace _dali.widgets
/** /**
*/ */
private async update_table( private async update_table(
) ) : Promise<void>
: Promise<void>
{ {
/** /**
* @todo avoid? * @todo avoid?
@ -842,8 +834,7 @@ namespace _dali.widgets
= =
{ {
} }
) ) : void
: void
{ {
this.container.querySelectorAll(".weekview-event_entry").forEach( this.container.querySelectorAll(".weekview-event_entry").forEach(
(element) => { (element) => {
@ -871,8 +862,7 @@ namespace _dali.widgets
*/ */
public async load( public async load(
target_element : Element target_element : Element
) ) : Promise<void>
: Promise<void>
{ {
target_element.innerHTML = await _dali.helpers.template_coin( target_element.innerHTML = await _dali.helpers.template_coin(
"widget-weekview", "widget-weekview",

View file

@ -10,16 +10,29 @@
text-align: center; text-align: center;
} }
.weekview-controls > * .weekview-control
{ {
flex-basis: 0; flex-basis: 0;
flex-grow: 0; flex-grow: 0;
flex-shrink: 1; flex-shrink: 1;
margin: 0 0 0 16px; min-width: 80px;
margin: 0 0 0 8px;
}
.weekview-controls .widget-special_number_input
{
flex-basis: 0;
flex-grow: 0;
flex-shrink: 1;
min-width: 140px;
margin: 0 0 0 8px;
} }
.weekview-control-label .weekview-control-label
,
.weekview-controls .widget-special_number_input-label
{ {
display: block; display: block;
@ -29,6 +42,16 @@
*/ */
} }
.weekview-control-input > *
{
display: inline-block;
}
.weekview-controls .widget-special_number_input input
{
max-width: 40px;
}
.weekview-table table .weekview-table table
{ {
width: 100%; width: 100%;

View file

@ -30,14 +30,21 @@ ${dir_build}/index.html: \
.PHONY: templates .PHONY: templates
templates: \ templates: \
templates-widgets-login \
templates-widgets-special_number_input \ templates-widgets-special_number_input \
templates-widgets-login_oidc \
templates-widgets-sources \ templates-widgets-sources \
templates-widgets-caldav \
templates-widgets-listview \ templates-widgets-listview \
templates-widgets-weekview \ templates-widgets-weekview \
templates-widgets-overview \ templates-widgets-mode_switcher \
templates-widgets-mode_switcher templates-pages-caldav \
templates-pages-overview
.PHONY: templates-widgets-login
templates-widgets-login: \
$(wildcard ${dir_source}/widgets/login/templates/*)
@ ${cmd_log} "templates:widget:login …"
@ ${cmd_mkdir} ${dir_build}/templates/widget-login
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/login/templates/* ${dir_build}/templates/widget-login/
.PHONY: templates-widgets-special_number_input .PHONY: templates-widgets-special_number_input
templates-widgets-special_number_input: \ templates-widgets-special_number_input: \
@ -46,13 +53,6 @@ templates-widgets-special_number_input: \
@ ${cmd_mkdir} ${dir_build}/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/ @ ${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-sources .PHONY: templates-widgets-sources
templates-widgets-sources: \ templates-widgets-sources: \
$(wildcard ${dir_source}/widgets/sources/templates/*) $(wildcard ${dir_source}/widgets/sources/templates/*)
@ -60,13 +60,6 @@ templates-widgets-sources: \
@ ${cmd_mkdir} ${dir_build}/templates/widget-sources @ ${cmd_mkdir} ${dir_build}/templates/widget-sources
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/sources/templates/* ${dir_build}/templates/widget-sources/ @ ${cmd_cp} -r -u -v ${dir_source}/widgets/sources/templates/* ${dir_build}/templates/widget-sources/
.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 .PHONY: templates-widgets-listview
templates-widgets-listview: \ templates-widgets-listview: \
$(wildcard ${dir_source}/widgets/listview/templates/*) $(wildcard ${dir_source}/widgets/listview/templates/*)
@ -81,13 +74,6 @@ templates-widgets-weekview: \
@ ${cmd_mkdir} ${dir_build}/templates/widget-weekview @ ${cmd_mkdir} ${dir_build}/templates/widget-weekview
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/weekview/templates/* ${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-widgets-mode_switcher .PHONY: templates-widgets-mode_switcher
templates-widgets-mode_switcher: \ templates-widgets-mode_switcher: \
$(wildcard ${dir_source}/widgets/mode_switcher/templates/*) $(wildcard ${dir_source}/widgets/mode_switcher/templates/*)
@ -95,12 +81,27 @@ templates-widgets-mode_switcher: \
@ ${cmd_mkdir} ${dir_build}/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/ @ ${cmd_cp} -r -u -v ${dir_source}/widgets/mode_switcher/templates/* ${dir_build}/templates/widget-mode_switcher/
.PHONY: templates-pages-caldav
templates-pages-caldav: \
$(wildcard ${dir_source}/pages/caldav/templates/*)
@ ${cmd_log} "templates:page:caldav …"
@ ${cmd_mkdir} ${dir_build}/templates/caldav
@ ${cmd_cp} -r -u -v ${dir_source}/pages/caldav/templates/* ${dir_build}/templates/caldav/
.PHONY: templates-pages-overview
templates-pages-overview: \
$(wildcard ${dir_source}/pages/overview/templates/*)
@ ${cmd_log} "templates:page:overview …"
@ ${cmd_mkdir} ${dir_build}/templates/overview
@ ${cmd_cp} -r -u -v ${dir_source}/pages/overview/templates/* ${dir_build}/templates/overview/
.PHONY: style .PHONY: style
style: ${dir_build}/style.css style: ${dir_build}/style.css
${dir_build}/style.css: \ ${dir_build}/style.css: \
$(wildcard ${dir_source}/style/*.css) \ $(wildcard ${dir_source}/style/*.css) \
$(wildcard ${dir_source}/widgets/*/style.css) $(wildcard ${dir_source}/widgets/*/style.css) \
$(wildcard ${dir_source}/pages/*/style.css)
@ ${cmd_log} "style …" @ ${cmd_log} "style …"
@ ${cmd_mkdir} ${dir_build} @ ${cmd_mkdir} ${dir_build}
@ ${cmd_cat} $^ > $@ @ ${cmd_cat} $^ > $@
@ -115,9 +116,10 @@ ${dir_temp}/logic-unlinked.js: \
${dir_source}/base.ts \ ${dir_source}/base.ts \
${dir_source}/types.ts \ ${dir_source}/types.ts \
${dir_source}/model.ts \ ${dir_source}/model.ts \
${dir_source}/overlay.ts \
${dir_source}/helpers.ts \ ${dir_source}/helpers.ts \
${dir_source}/overlay.ts \
$(wildcard ${dir_source}/widgets/*/logic.ts) \ $(wildcard ${dir_source}/widgets/*/logic.ts) \
$(wildcard ${dir_source}/pages/*/logic.ts) \
${dir_source}/main.ts ${dir_source}/main.ts
@ ${cmd_log} "logic | compile …" @ ${cmd_log} "logic | compile …"
@ ${cmd_mkdir} $(dir $@) @ ${cmd_mkdir} $(dir $@)