From dc6abdc2e0c3e771fc9e8596dc8b1604b8a16517 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Mon, 13 Oct 2025 13:29:19 +0200 Subject: [PATCH 1/9] [task-408] Widgets von Plankton --- lib/plankton/plankton.d.ts | 98 +++---- lib/plankton/plankton.js | 368 +++++++++++++------------- source/base/widget.ts | 18 -- source/pages/overview/logic.ts | 2 +- source/widgets/listview/logic.ts | 3 +- source/widgets/mode_switcher/logic.ts | 3 +- source/widgets/sources/logic.ts | 3 +- source/widgets/weekview/logic.ts | 3 +- tools/makefile | 1 - tools/update-plankton | 1 + 10 files changed, 239 insertions(+), 261 deletions(-) delete mode 100644 source/base/widget.ts diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 91457ef..3302bcf 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -3809,55 +3809,6 @@ declare namespace lib_plankton.translate { */ function stance(str: string): string; } -declare namespace lib_plankton.zoo_page { - /** - */ - export type type_location = { - name: string; - parameters: Record; - }; - /** - */ - type type_handler = ((parameters: Record, target_element: Element) => void); - /** - */ - type type_nav_entry_definition = { - location: type_location; - label: string; - groups: Array; - }; - /** - */ - export let _pool: Record; - /** - */ - export function encode(location: type_location): string; - /** - * encodes a location in the URL and loads it - */ - export function set(location: type_location): void; - /** - */ - export function reload(): Promise; - /** - */ - export function register(location_name: string, handler: type_handler): void; - /** - */ - export function nav_set_groups(groups: (null | Array)): void; - /** - */ - export function init(target_element: Element, { "pool": pool, "fallback": fallback, "nav_entries": nav_entries, "nav_initial_groups": nav_initial_groups, }?: { - pool?: Record; - fallback?: (null | type_location); - nav_entries?: Array; - nav_initial_groups?: (null | Array); - }): void; - /** - */ - export function start(): void; - export {}; -} declare namespace lib_plankton.zoo_widget { /** */ @@ -4043,6 +3994,55 @@ declare namespace lib_plankton.zoo_widget { load(target_element: HTMLElement): Promise; } } +declare namespace lib_plankton.zoo_page { + /** + */ + export type type_location = { + name: string; + parameters: Record; + }; + /** + */ + type type_handler = ((parameters: Record, target_element: Element) => void); + /** + */ + type type_nav_entry_definition = { + location: type_location; + label: string; + groups: Array; + }; + /** + */ + export let _pool: Record; + /** + */ + export function encode(location: type_location): string; + /** + * encodes a location in the URL and loads it + */ + export function set(location: type_location): void; + /** + */ + export function reload(): Promise; + /** + */ + export function register(location_name: string, handler: type_handler): void; + /** + */ + export function nav_set_groups(groups: (null | Array)): void; + /** + */ + export function init(target_element: Element, { "pool": pool, "fallback": fallback, "nav_entries": nav_entries, "nav_initial_groups": nav_initial_groups, }?: { + pool?: Record; + fallback?: (null | type_location); + nav_entries?: Array; + nav_initial_groups?: (null | Array); + }): void; + /** + */ + export function start(): void; + export {}; +} declare namespace lib_plankton.zoo_input { /** * @author fenris diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 6ff86ef..64e504d 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -11738,190 +11738,6 @@ var lib_plankton; })(translate = lib_plankton.translate || (lib_plankton.translate = {})); })(lib_plankton || (lib_plankton = {})); /* -This file is part of »bacterio-plankton:zoo-page«. - -Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:zoo-page« 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. - -»bacterio-plankton:zoo-page« 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 »bacterio-plankton:zoo-page«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var zoo_page; - (function (zoo_page) { - /** - */ - zoo_page._pool = {}; - /** - */ - let _fallback = null; - /** - */ - let _current = null; - /** - */ - let _target_element = null; - /** - */ - let _nav_entries; - /** - */ - function encode(location) { - return ("#" - + - ([location.name] - .concat(Object.entries(location.parameters) - .filter(([key, value]) => (value !== null)) - .map(([key, value]) => (key + "=" + value))))); - } - zoo_page.encode = encode; - /** - */ - function decode(encoded) { - if (encoded === "") { - return null; - } - else { - if (!encoded.startsWith("#")) { - return null; - } - else { - const parts = encoded.slice(1).split(","); - return { - "name": parts[0], - "parameters": Object.fromEntries(parts.slice(1) - .map(part => { - const parts_ = part.split("="); - return [parts_[0], parts_[1]]; - })), - }; - } - } - } - /** - * renders a page to the main element - */ - async function load(location) { - // _target_element.innerHTML = "[loading …]"; - _target_element.innerHTML = ""; - if (location === null) { - // do nothing - } - else { - if (!(location.name in zoo_page._pool)) { - _target_element.innerHTML = "not found"; - } - else { - await zoo_page._pool[location.name](location.parameters, _target_element); - _current = location; - } - } - } - /** - * retrieves the location from the set URL - */ - function get() { - return decode(window.location.hash); - } - /** - * encodes a location in the URL and loads it - */ - function set(location) { - window.location.hash = encode(location); - } - zoo_page.set = set; - /** - */ - function reload() { - return load(get()); - } - zoo_page.reload = reload; - /** - */ - function register(location_name, handler) { - zoo_page._pool[location_name] = handler; - } - zoo_page.register = register; - /** - */ - function nav_set_groups(groups) { - _nav_entries.forEach(nav_entry => { - const active = ((groups === null) - || - groups.some(group => nav_entry.definition.groups.includes(group))); - nav_entry.element.classList.toggle("active", active); - }); - } - zoo_page.nav_set_groups = nav_set_groups; - /** - */ - function init(target_element, { "pool": pool = {}, "fallback": fallback = null, "nav_entries": nav_entries = [], "nav_initial_groups": nav_initial_groups = null, } = {}) { - _target_element = target_element; - _fallback = fallback; - Object.entries(pool).forEach(([location_name, handler]) => { - register(location_name, handler); - }); - window.addEventListener("hashchange", () => { - const location_old = _current; - const location_new = (get() ?? _fallback); - if (((location_old === null) - && - (location_new !== null)) - || - ((location_old !== null) - && - (location_new !== null) - && - (location_old.name !== location_new.name))) { - load(location_new); - } - else { - // do nothing - } - }); - // nav - { - let ul_element = document.querySelector("nav > ul"); - _nav_entries = nav_entries.map(nav_entry_definition => { - let li_element = document.createElement("li"); - { - let a_element = document.createElement("a"); - a_element.setAttribute("href", encode(nav_entry_definition.location)); - a_element.textContent = (nav_entry_definition.label ?? nav_entry_definition.location.name); - li_element.appendChild(a_element); - } - ul_element.appendChild(li_element); - return { - "definition": nav_entry_definition, - "element": li_element, - }; - }); - nav_set_groups(nav_initial_groups); - } - } - zoo_page.init = init; - /** - */ - function start() { - const location = (get() ?? _fallback); - set(location); - load(location); - } - zoo_page.start = start; - })(zoo_page = lib_plankton.zoo_page || (lib_plankton.zoo_page = {})); -})(lib_plankton || (lib_plankton = {})); -/* This file is part of »bacterio-plankton:zoo-widget«. Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' @@ -12441,6 +12257,190 @@ var lib_plankton; })(zoo_widget = lib_plankton.zoo_widget || (lib_plankton.zoo_widget = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:zoo-page«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:zoo-page« 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. + +»bacterio-plankton:zoo-page« 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 »bacterio-plankton:zoo-page«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var zoo_page; + (function (zoo_page) { + /** + */ + zoo_page._pool = {}; + /** + */ + let _fallback = null; + /** + */ + let _current = null; + /** + */ + let _target_element = null; + /** + */ + let _nav_entries; + /** + */ + function encode(location) { + return ("#" + + + ([location.name] + .concat(Object.entries(location.parameters) + .filter(([key, value]) => (value !== null)) + .map(([key, value]) => (key + "=" + value))))); + } + zoo_page.encode = encode; + /** + */ + function decode(encoded) { + if (encoded === "") { + return null; + } + else { + if (!encoded.startsWith("#")) { + return null; + } + else { + const parts = encoded.slice(1).split(","); + return { + "name": parts[0], + "parameters": Object.fromEntries(parts.slice(1) + .map(part => { + const parts_ = part.split("="); + return [parts_[0], parts_[1]]; + })), + }; + } + } + } + /** + * renders a page to the main element + */ + async function load(location) { + // _target_element.innerHTML = "[loading …]"; + _target_element.innerHTML = ""; + if (location === null) { + // do nothing + } + else { + if (!(location.name in zoo_page._pool)) { + _target_element.innerHTML = "not found"; + } + else { + await zoo_page._pool[location.name](location.parameters, _target_element); + _current = location; + } + } + } + /** + * retrieves the location from the set URL + */ + function get() { + return decode(window.location.hash); + } + /** + * encodes a location in the URL and loads it + */ + function set(location) { + window.location.hash = encode(location); + } + zoo_page.set = set; + /** + */ + function reload() { + return load(get()); + } + zoo_page.reload = reload; + /** + */ + function register(location_name, handler) { + zoo_page._pool[location_name] = handler; + } + zoo_page.register = register; + /** + */ + function nav_set_groups(groups) { + _nav_entries.forEach(nav_entry => { + const active = ((groups === null) + || + groups.some(group => nav_entry.definition.groups.includes(group))); + nav_entry.element.classList.toggle("active", active); + }); + } + zoo_page.nav_set_groups = nav_set_groups; + /** + */ + function init(target_element, { "pool": pool = {}, "fallback": fallback = null, "nav_entries": nav_entries = [], "nav_initial_groups": nav_initial_groups = null, } = {}) { + _target_element = target_element; + _fallback = fallback; + Object.entries(pool).forEach(([location_name, handler]) => { + register(location_name, handler); + }); + window.addEventListener("hashchange", () => { + const location_old = _current; + const location_new = (get() ?? _fallback); + if (((location_old === null) + && + (location_new !== null)) + || + ((location_old !== null) + && + (location_new !== null) + && + (location_old.name !== location_new.name))) { + load(location_new); + } + else { + // do nothing + } + }); + // nav + { + let ul_element = document.querySelector("nav > ul"); + _nav_entries = nav_entries.map(nav_entry_definition => { + let li_element = document.createElement("li"); + { + let a_element = document.createElement("a"); + a_element.setAttribute("href", encode(nav_entry_definition.location)); + a_element.textContent = (nav_entry_definition.label ?? nav_entry_definition.location.name); + li_element.appendChild(a_element); + } + ul_element.appendChild(li_element); + return { + "definition": nav_entry_definition, + "element": li_element, + }; + }); + nav_set_groups(nav_initial_groups); + } + } + zoo_page.init = init; + /** + */ + function start() { + const location = (get() ?? _fallback); + set(location); + load(location); + } + zoo_page.start = start; + })(zoo_page = lib_plankton.zoo_page || (lib_plankton.zoo_page = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:zoo-input«. Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' diff --git a/source/base/widget.ts b/source/base/widget.ts deleted file mode 100644 index f971ca8..0000000 --- a/source/base/widget.ts +++ /dev/null @@ -1,18 +0,0 @@ -namespace _dali -{ - - /** - * @todo outsource - */ - export abstract class class_widget - { - - /** - */ - public abstract load( - target_element : Element - ) : Promise; - - } - -} diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index 7caeb15..e6dd23b 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -27,7 +27,7 @@ namespace _dali.pages.overview // mode switcher { - const widget_mode_switcher : _dali.class_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher( + const widget_mode_switcher : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher( [ { "mode": _dali.type.enum_view_mode.week, diff --git a/source/widgets/listview/logic.ts b/source/widgets/listview/logic.ts index 9523e4c..c79f673 100644 --- a/source/widgets/listview/logic.ts +++ b/source/widgets/listview/logic.ts @@ -28,7 +28,7 @@ namespace _dali.widgets.listview /** */ - export class class_widget_listview extends _dali.class_widget + export class class_widget_listview implements lib_plankton.zoo_widget.interface_widget { /** @@ -94,7 +94,6 @@ namespace _dali.widgets.listview }, options ); - super(); this.get_entries = get_entries; this.container = null; this.action_select_event = options.action_select_event; diff --git a/source/widgets/mode_switcher/logic.ts b/source/widgets/mode_switcher/logic.ts index 50a8e53..fd7c9b0 100644 --- a/source/widgets/mode_switcher/logic.ts +++ b/source/widgets/mode_switcher/logic.ts @@ -11,7 +11,7 @@ namespace _dali.widgets.mode_switcher /** */ - export class class_widget_mode_switcher extends _dali.class_widget + export class class_widget_mode_switcher implements lib_plankton.zoo_widget.interface_widget { /** @@ -47,7 +47,6 @@ namespace _dali.widgets.mode_switcher } ) { - super(); this.options = options; this.initial_selection = initial_selection; this.action_change = action_change; diff --git a/source/widgets/sources/logic.ts b/source/widgets/sources/logic.ts index e9b57da..01c082c 100644 --- a/source/widgets/sources/logic.ts +++ b/source/widgets/sources/logic.ts @@ -13,7 +13,7 @@ namespace _dali.widgets.sources /** */ - export class class_widget_sources extends _dali.class_widget + export class class_widget_sources implements lib_plankton.zoo_widget.interface_widget { /** @@ -53,7 +53,6 @@ namespace _dali.widgets.sources }, options ); - super(); this.keys = []; this.data = {}; entries.forEach( diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index 85686df..e788043 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -28,7 +28,7 @@ namespace _dali.widgets.weekview /** */ - export class class_widget_weekview extends _dali.class_widget + export class class_widget_weekview implements lib_plankton.zoo_widget.interface_widget { /** @@ -96,7 +96,6 @@ namespace _dali.widgets.weekview }, options ); - super(); this.get_entries = get_entries; this.container = null; this.action_select_day = options.action_select_day; diff --git a/tools/makefile b/tools/makefile index 3195a2b..dcc4413 100644 --- a/tools/makefile +++ b/tools/makefile @@ -134,7 +134,6 @@ logic: ${dir_build}/logic.js ${dir_temp}/logic-unlinked.js: \ ${dir_lib}/plankton/plankton.d.ts \ ${dir_source}/base/helpers.ts \ - ${dir_source}/base/widget.ts \ ${dir_source}/base/types.ts \ ${dir_source}/base/functions.ts \ ${dir_source}/resources/conf.ts \ diff --git a/tools/update-plankton b/tools/update-plankton index 7577b00..dad2426 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -23,6 +23,7 @@ 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" -- 2.47.3 From c97fd370407506949dfff4958cad8a868b30f1a8 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 00:16:22 +0200 Subject: [PATCH 2/9] [task-408] [int] --- lib/plankton/plankton.js | 2 +- misc/conf-example.json | 2 +- source/data/localization/deu.loc.json | 11 +- source/data/localization/eng.loc.json | 11 +- source/index.html.tpl | 4 + source/main.ts | 1 + source/overlay.ts | 75 +++++ source/pages/calendar_edit/logic.ts | 203 +++---------- source/pages/event_add/logic.ts | 235 --------------- .../event_add/templates/default.html.tpl | 5 - source/pages/event_edit/logic.ts | 195 ------------ .../event_edit/templates/default.html.tpl | 5 - source/pages/overview/logic.ts | 247 ++++++++++++--- source/resources/backend.ts | 1 + source/style/main.css | 33 ++ source/widgets/calendar_edit/logic.ts | 217 ++++++++++++++ source/widgets/event_edit/logic.ts | 282 ++++++++++++++++++ source/widgets/weekview/logic.ts | 51 +++- tools/makefile | 37 +-- 19 files changed, 928 insertions(+), 689 deletions(-) create mode 100644 source/overlay.ts delete mode 100644 source/pages/event_add/logic.ts delete mode 100644 source/pages/event_add/templates/default.html.tpl delete mode 100644 source/pages/event_edit/logic.ts delete mode 100644 source/pages/event_edit/templates/default.html.tpl create mode 100644 source/widgets/calendar_edit/logic.ts create mode 100644 source/widgets/event_edit/logic.ts diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 64e504d..0a4b816 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -9940,7 +9940,7 @@ var lib_plankton; h = 0; } else if (q === r) { - h = ((0 / 3) + ((g - b) / (c * 6))); + h = ((0 / 3) + lib_plankton.math.mod((g - b) / (c * 6), 1)); } else if (q === g) { h = ((1 / 3) + ((b - r) / (c * 6))); diff --git a/misc/conf-example.json b/misc/conf-example.json index 7f8190c..cf5b37e 100644 --- a/misc/conf-example.json +++ b/misc/conf-example.json @@ -8,6 +8,6 @@ }, "misc": { "oidc_redirect_uri_template": "http://localhost:8888/#oidc_finish,session_key={{session_key}}", - "use_central_europe_specific_datetime_inputs": false + "use_central_europe_specific_datetime_inputs": true } } diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 1ddbdb1..52bdc5b 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -18,6 +18,7 @@ "common.edit": "bearbeiten", "common.show": "zeigen", "common.hide": "ausblenden", + "common.cancel": "abbrechen", "access_level.none": "nichts", "access_level.view": "nur lesen", "access_level.edit": "lesen und bearbeiten", @@ -49,6 +50,11 @@ "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", "widget.weekview.controls.apply": "Laden", + "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", "page.login.title": "Anmelden", "page.login.internal.name": "Name", "page.login.internal.password": "Kennwort", @@ -70,14 +76,9 @@ "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", "page.overview.mode.week": "Wochen-Ansicht", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 25ad7bf..023e8d2 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -18,6 +18,7 @@ "common.edit": "edit", "common.show": "show", "common.hide": "hide", + "common.cancel": "cancel", "access_level.none": "none", "access_level.view": "read only", "access_level.edit": "read and write", @@ -49,6 +50,11 @@ "widget.weekview.controls.week": "Week", "widget.weekview.controls.count": "Count", "widget.weekview.controls.apply": "Load", + "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", "page.login.title": "Login", "page.login.internal.name": "name", "page.login.internal.password": "password", @@ -69,15 +75,10 @@ "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", "page.overview.mode.week": "week view", diff --git a/source/index.html.tpl b/source/index.html.tpl index e8eb5f4..d8151a6 100644 --- a/source/index.html.tpl +++ b/source/index.html.tpl @@ -31,6 +31,10 @@ document.addEventListener( +
+
+
+
diff --git a/source/main.ts b/source/main.ts index 1713e10..6998722 100644 --- a/source/main.ts +++ b/source/main.ts @@ -109,6 +109,7 @@ namespace _dali } ); await update(); + await _dali.overlay.initialize(); lib_plankton.call.loop( () => { update(); diff --git a/source/overlay.ts b/source/overlay.ts new file mode 100644 index 0000000..6195c85 --- /dev/null +++ b/source/overlay.ts @@ -0,0 +1,75 @@ +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 + { + 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(undefined); + } + +} diff --git a/source/pages/calendar_edit/logic.ts b/source/pages/calendar_edit/logic.ts index 0ed083d..8221f13 100644 --- a/source/pages/calendar_edit/logic.ts +++ b/source/pages/calendar_edit/logic.ts @@ -16,170 +16,51 @@ namespace _dali.pages "label": lib_plankton.translate.get("page.calendar_edit.title.regular") } ); - const form : lib_plankton.zoo_form.class_form< - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - }, - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - } - > = new lib_plankton.zoo_form.class_form< - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - }, - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - } - >( - (value) => value, - (raw) => raw, - new lib_plankton.zoo_input.class_input_group( - [ - { - "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", - "input": await _dali.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"), - "procedure": async (get_value, get_representation) => { - const data : any = await get_value(); - try { - await _dali.backend.calendar_change( - calendar_id, - data - ); - 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"), - "procedure": async (get_value, get_representation) => { - try { - await _dali.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 : _dali.type.calendar_object = await _dali.backend.calendar_get( calendar_id ); - await form.input_write(calendar_object); + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + { + "read_only": read_only, + "action_change": (data) => { + _dali.backend.calendar_change( + calendar_id, + data + ) + .then( + () => { + lib_plankton.zoo_page.set( + { + "name": "overview", + "parameters": {} + } + ); + } + ); + }, + "action_remove": (data) => { + _dali.backend.calendar_remove( + calendar_id + ) + .then( + () => { + lib_plankton.zoo_page.set( + { + "name": "overview", + "parameters": {} + } + ); + } + ); + }, + "initial_value": { + "name": calendar_object.name, + "hue": calendar_object.hue, + "access": calendar_object.access, + }, + } + ); + await widget.load(document.querySelector("#calendar_edit_form")); return Promise.resolve(undefined); } ); diff --git a/source/pages/event_add/logic.ts b/source/pages/event_add/logic.ts deleted file mode 100644 index f5b5d90..0000000 --- a/source/pages/event_add/logic.ts +++ /dev/null @@ -1,235 +0,0 @@ -namespace _dali.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 _dali.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 : _dali.type.calendar_id; - event_object : _dali.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 : _dali.type.calendar_id; - event_object : _dali.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( - [ - { - "name": "calendar_id", - "input": new lib_plankton.zoo_input.class_input_selection( - ( - (await _dali.backend.calendar_list()) - .filter( - (entry) => ( - (entry.access_level === _dali.type.enum_access_level.edit) - || - (entry.access_level === _dali.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": _dali.helpers.datetime_input(), - "label": lib_plankton.translate.get("event.begin") - }, - { - "name": "end", - "input": new lib_plankton.zoo_input.class_input_soft( - _dali.helpers.datetime_input() - ), - "label": lib_plankton.translate.get("event.end") - }, - { - "name": "location", - "input": new lib_plankton.zoo_input.class_input_soft( - 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( - 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( - 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 _dali.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(undefined); - } - ); - -} diff --git a/source/pages/event_add/templates/default.html.tpl b/source/pages/event_add/templates/default.html.tpl deleted file mode 100644 index 3cfad06..0000000 --- a/source/pages/event_add/templates/default.html.tpl +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{label}}

-
-
-
diff --git a/source/pages/event_edit/logic.ts b/source/pages/event_edit/logic.ts deleted file mode 100644 index 4e4bab6..0000000 --- a/source/pages/event_edit/logic.ts +++ /dev/null @@ -1,195 +0,0 @@ -namespace _dali.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 _dali.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< - _dali.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< - _dali.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( - [ - { - "name": "name", - "input": new lib_plankton.zoo_input.class_input_text( - ), - "label": lib_plankton.translate.get("event.name") - }, - { - "name": "begin", - "input": _dali.helpers.datetime_input(), - "label": lib_plankton.translate.get("event.begin") - }, - { - "name": "end", - "input": new lib_plankton.zoo_input.class_input_soft( - _dali.helpers.datetime_input() - ), - "label": lib_plankton.translate.get("event.end") - }, - { - "name": "location", - "input": new lib_plankton.zoo_input.class_input_soft( - 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( - 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( - 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 _dali.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 _dali.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 : _dali.type.event_object = await _dali.backend.calendar_event_get( - calendar_id, - event_id - ); - await form.input_write( - event_object - ); - return Promise.resolve(undefined); - } - ); - -} diff --git a/source/pages/event_edit/templates/default.html.tpl b/source/pages/event_edit/templates/default.html.tpl deleted file mode 100644 index 2d47742..0000000 --- a/source/pages/event_edit/templates/default.html.tpl +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{label}}

-
-
-
diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index e6dd23b..e798974 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -17,6 +17,13 @@ namespace _dali.pages.overview target_element.querySelector("#overview").classList.toggle("overview-compact", compact); }; + /** + * @todo geschickter bauen (MVC, MVVM, …) + */ + const update = () => { + lib_plankton.zoo_page.reload(); + }; + // exec target_element.innerHTML = await _dali.helpers.template_coin( "overview", @@ -85,6 +92,7 @@ namespace _dali.pages.overview data, { "action_open": (entry) => { + let read_only : boolean; switch (entry.access_level) { case _dali.type.enum_access_level.none: @@ -95,31 +103,60 @@ namespace _dali.pages.overview case _dali.type.enum_access_level.edit: case _dali.type.enum_access_level.view: { - lib_plankton.zoo_page.set( - { - "name": "calendar_edit", - "parameters": { - "read_only": "yes", - "calendar_id": entry.id, - } - } - ); + read_only = true; break; } case _dali.type.enum_access_level.admin: { - lib_plankton.zoo_page.set( - { - "name": "calendar_edit", - "parameters": { - "read_only": "no", - "calendar_id": entry.id, - } - } - ); + read_only = false; break; } } + (async () => { + const calendar_id : _dali.type.calendar_id = entry.id; + const calendar_object : _dali.type.calendar_object = await _dali.backend.calendar_get( + calendar_id + ); + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + { + "read_only": read_only, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_change": (data) => { + _dali.backend.calendar_change( + calendar_id, + data + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ); + }, + "action_remove": (data) => { + _dali.backend.calendar_remove( + calendar_id + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ); + }, + "initial_value": { + "name": calendar_object.name, + "hue": calendar_object.hue, + "access": calendar_object.access, + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }, "action_toggle_visibility": (entry) => { widget_weekview.toggle_visibility(entry.id); @@ -139,6 +176,7 @@ namespace _dali.pages.overview } ); const action_select_event = (calendar_id, access_level, event_id) => { + let read_only : boolean; switch (access_level) { case _dali.type.enum_access_level.none: @@ -148,34 +186,90 @@ namespace _dali.pages.overview } case _dali.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, - } - } - ); + read_only = true; break; } case _dali.type.enum_access_level.edit: case _dali.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, - } - } - ); + read_only = false; break; } } + (async () => { + const event_object : _dali.type.event_object = await _dali.backend.calendar_event_get( + calendar_id, + event_id + ); + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + { + "calendar_id": calendar_id, + "event_name": event_object.name, + "event_begin": event_object.begin, + "event_end": event_object.end, + "event_location": event_object.location, + "event_link": event_object.link, + "event_description": event_object.description, + }, + { + "read_only": read_only, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_change": (data) => { + _dali.backend.calendar_event_change( + calendar_id, + event_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( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_change.error", + {"details": String(reason)} + ); + } + ); + }, + "action_remove": () => { + _dali.backend.calendar_event_remove( + calendar_id, + event_id + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_remove_error", + {"details": String(reason)} + ); + } + ); + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }; // listview { @@ -210,17 +304,76 @@ namespace _dali.pages.overview { "action_select_event": action_select_event, "action_select_day": (date) => { - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { + (async () => { + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + { "calendar_id": null, - "year": date.year, - "month": date.month, - "day": date.day, + "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.backend.calendar_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( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + // todo + } + ); + }, } - } - ); + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }, } ) diff --git a/source/resources/backend.ts b/source/resources/backend.ts index 1164246..9991f92 100644 --- a/source/resources/backend.ts +++ b/source/resources/backend.ts @@ -547,6 +547,7 @@ namespace _dali.backend /** + * @todo Möglichkeit den Kalender zu ändern */ export async function calendar_event_change( calendar_id : _dali.type.calendar_id, diff --git a/source/style/main.css b/source/style/main.css index e1d417e..ea384f0 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -20,6 +20,39 @@ header margin-bottom: 16px; } +#overlay +{ + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + z-index: 2; +} + +#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; +} + nav > ul { list-style-type: none; diff --git a/source/widgets/calendar_edit/logic.ts b/source/widgets/calendar_edit/logic.ts new file mode 100644 index 0000000..ac45f84 --- /dev/null +++ b/source/widgets/calendar_edit/logic.ts @@ -0,0 +1,217 @@ +namespace _dali.widgets.calendar_edit +{ + + /** + */ + export type type_value = { + name : string; + hue : float; + access : { + public : boolean; + default_level : _dali.type.enum_access_level; + attributed : lib_plankton.map.type_map< + _dali.type.user_id, + _dali.type.enum_access_level + >; + }; + }; + + + /** + */ + export class class_widget_calendar_edit + implements lib_plankton.zoo_widget.interface_widget + { + + /** + */ + private read_only : boolean; + + + /** + */ + private action_cancel ?: (null | (() => void)); + + + /** + */ + private action_change ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_remove ?: (null | ((value : type_value) => void)); + + + /** + */ + private initial_value : (null | type_value); + + + /** + */ + public constructor( + { + "read_only": read_only = false, + "action_cancel": action_cancel = null, + "action_change": action_change = null, + "action_remove": action_remove = null, + "initial_value": initial_value = null, + } + : + { + read_only ?: boolean; + action_cancel ?: (null | (() => void)); + action_change ?: (null | ((value : type_value) => void)); + action_remove ?: (null | ((value : type_value) => void)); + initial_value ?: (null | type_value); + } + = + { + } + ) + { + this.read_only = read_only; + this.action_cancel = action_cancel; + this.action_change = action_change; + this.action_remove = action_remove; + this.initial_value = initial_value; + } + + + /** + * [implementation] + */ + public async load( + target_element : HTMLElement + ) : Promise + { + const form : lib_plankton.zoo_form.class_form< + type_value, + type_value + > = new lib_plankton.zoo_form.class_form< + type_value, + type_value + >( + (value) => value, + (raw) => raw, + new lib_plankton.zoo_input.class_input_group( + [ + { + "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", + "input": await _dali.helpers.input_attributed_access(), + "label": lib_plankton.translate.get("calendar.access.attributed"), + }, + ] + ), + "label": lib_plankton.translate.get("calendar.access.access"), + }, + ] + ), + ( + [] + // cancel + .concat( + (! (this.action_cancel === null)) + ? + [ + { + "label": lib_plankton.translate.get("common.cancel"), + "procedure": async () => { + this.action_cancel(); + } + }, + ] + : + [] + ) + // 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 : type_value = await get_value(); + this.action_change(value); + } + }, + ] + : + [] + ) + // remove + .concat( + ((! this.read_only) && (! (this.action_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.calendar_edit.actions.remove"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_remove(value); + } + }, + ] + : + [] + ) + ) + ); + await form.setup(target_element); + await form.input_write( + (! (this.initial_value === null)) + ? + this.initial_value + : + { + "name": "", + "hue": lib_plankton.random.generate_unit(), + "access": { + "public": false, + "default_level": _dali.type.enum_access_level.view, + "attributed": lib_plankton.map.hashmap.implementation_map< + _dali.type.user_id, + _dali.type.enum_access_level + >( + lib_plankton.map.hashmap.make< + _dali.type.user_id, + _dali.type.enum_access_level + >( + user_id => user_id.toFixed(0), + ) + ), + }, + } + ); + } + + } + +} diff --git a/source/widgets/event_edit/logic.ts b/source/widgets/event_edit/logic.ts new file mode 100644 index 0000000..7d1b942 --- /dev/null +++ b/source/widgets/event_edit/logic.ts @@ -0,0 +1,282 @@ +namespace _dali.widgets.event_edit +{ + + /** + */ + 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 + { + + /** + */ + private read_only : boolean; + + + /** + */ + private action_cancel ?: (null | (() => void)); + + + /** + */ + private action_add ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_change ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_remove ?: (null | ((value : type_value) => void)); + + + /** + */ + private initial_value : type_value; + + + /** + */ + public constructor( + 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)); + } + = + { + } + ) + { + 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; + this.initial_value = initial_value; + } + + + /** + * [implementation] + */ + public async load( + target_element : HTMLElement + ) : Promise + { + const available_calendars : Array< + { + id : int; + name : string; + hue : float; + access_level : _dali.type.enum_access_level; + } + > = ( + (await _dali.backend.calendar_list()) + .filter( + (entry) => ( + (entry.access_level === _dali.type.enum_access_level.edit) + || + (entry.access_level === _dali.type.enum_access_level.admin) + ) + ) + ); + 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 ?? 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( + [ + { + "name": "calendar_id", + "input": new lib_plankton.zoo_input.class_input_selection( + ( + 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( + _dali.helpers.datetime_input() + ), + "label": lib_plankton.translate.get("event.end") + }, + { + "name": "event_location", + "input": new lib_plankton.zoo_input.class_input_soft( + 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( + 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( + new lib_plankton.zoo_input.class_input_textarea( + ) + ), + "label": lib_plankton.translate.get("event.description") + }, + ] + ), + ( + [] + // cancel + .concat( + (! (this.action_cancel === null)) + ? + [ + { + "label": lib_plankton.translate.get("common.cancel"), + "procedure": async () => { + this.action_cancel(); + } + }, + ] + : + [] + ) + // 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_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.event_edit.actions.remove"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_remove(value); + } + }, + ] + : + [] + ) + ) + ); + await form.setup(target_element); + await form.input_write(this.initial_value); + } + + } + +} diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index e788043..c6a4484 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -833,6 +833,26 @@ namespace _dali.widgets.weekview } + /** + */ + private react_on_control_change( + dom_context : Element + ) : void + { + const year : int = parseInt((dom_context.querySelector(".weekview-control-year > input") as HTMLInputElement).value); + const week : int = parseInt((dom_context.querySelector(".weekview-control-week > input") as HTMLInputElement).value); + const count : int = parseInt((dom_context.querySelector(".weekview-control-count > input") as HTMLInputElement).value); + this.update( + year, + week, + count, + { + "update_controls": false, + } + ); + } + + /** */ public toggle_visibility( @@ -886,19 +906,28 @@ namespace _dali.widgets.weekview "click", (event) => { event.preventDefault(); - const year : int = parseInt((target_element.querySelector(".weekview-control-year > input") as HTMLInputElement).value); - const week : int = parseInt((target_element.querySelector(".weekview-control-week > input") as HTMLInputElement).value); - const count : int = parseInt((target_element.querySelector(".weekview-control-count > input") as HTMLInputElement).value); - this.update( - year, - week, - count, - { - "update_controls": false, - } - ); + this.react_on_control_change(target_element); } ); + if (false) + { + [ + "year", + "week", + "count", + ].forEach( + (name) => { + const selector : string = (".weekview-control-" + name + " > input"); + (target_element.querySelector(selector) as HTMLInputElement).addEventListener( + "change", + (event) => { + event.preventDefault(); + this.react_on_control_change(target_element); + } + ); + } + ); + } } // table { diff --git a/tools/makefile b/tools/makefile index dcc4413..89727f0 100644 --- a/tools/makefile +++ b/tools/makefile @@ -36,11 +36,11 @@ templates: \ templates-widgets-listview \ templates-widgets-weekview \ templates-widgets-mode_switcher \ + templates-widgets-calendar_edit \ + templates-widgets-event_edit \ 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 @@ -72,6 +72,20 @@ templates-widgets-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-widgets-calendar_edit +templates-widgets-calendar_edit: \ + $(wildcard ${dir_source}/widgets/calendar_edit/templates/*) + @ ${cmd_log} "templates:widgets: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}/pages/event_edit/templates/*) + @ ${cmd_log} "templates:widgets:event_edit …" + @ ${cmd_mkdir} ${dir_build}/templates/widget-event_edit + # @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/widget-uevent_edit/ + .PHONY: templates-pages-caldav templates-pages-caldav: \ $(wildcard ${dir_source}/pages/caldav/templates/*) @@ -93,20 +107,6 @@ templates-pages-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/*) @@ -142,14 +142,15 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/widgets/listview/logic.ts \ ${dir_source}/widgets/weekview/logic.ts \ ${dir_source}/widgets/mode_switcher/logic.ts \ + ${dir_source}/widgets/calendar_edit/logic.ts \ + ${dir_source}/widgets/event_edit/logic.ts \ + ${dir_source}/overlay.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}/main.ts @ ${cmd_log} "logic | compile …" -- 2.47.3 From 057b682bdc524a18316041ec2c266fb415fc5b28 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 15:56:29 +0200 Subject: [PATCH 3/9] [task-408] [int] --- source/base/model.ts | 8 + source/base/types.ts | 21 ++- source/widgets/weekview/logic.ts | 270 +++++++++++++++++++++++++++++-- tools/makefile | 1 + 4 files changed, 284 insertions(+), 16 deletions(-) create mode 100644 source/base/model.ts diff --git a/source/base/model.ts b/source/base/model.ts new file mode 100644 index 0000000..26847c6 --- /dev/null +++ b/source/base/model.ts @@ -0,0 +1,8 @@ +namespace _dali.model +{ + + /** + */ + let events : Array<_dali.type.event_entry> = []; + +} diff --git a/source/base/types.ts b/source/base/types.ts index da79c50..e97b1d9 100644 --- a/source/base/types.ts +++ b/source/base/types.ts @@ -31,6 +31,22 @@ namespace _dali.type }; + /** + * @todo deprecate? + */ + export 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 event_id = string; + + /** */ export type event_object = { @@ -61,7 +77,10 @@ namespace _dali.type /** */ - export type local_resource_event_id = int; + export type event_entry = { + id : event_id; + object : event_object; + }; /** diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index c6a4484..a6265a5 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -41,6 +41,14 @@ namespace _dali.widgets.weekview private container : (null | Element); + /** + */ + private event_map : lib_plankton.map.type_map< + _dali.type.event_id, + HTMLElement + >; + + /** */ private action_select_event : ( @@ -98,6 +106,14 @@ namespace _dali.widgets.weekview ); this.get_entries = get_entries; this.container = null; + this.event_map = lib_plankton.map.hashmap.implementation_map( + lib_plankton.map.hashmap.make< + _dali.type.event_id, + HTMLElement + >( + event_id => event_id + ) + ); this.action_select_day = options.action_select_day; this.action_select_event = options.action_select_event; } @@ -198,6 +214,215 @@ namespace _dali.widgets.weekview } + /** + */ + private create_dom_entry( + sources : lib_plankton.map.type_map< + _dali.type.calendar_id, + { + name : string; + access_level : _dali.type.enum_access_level; + /** + * @todo replace with hue? + */ + color : lib_plankton.color.type_color; + } + >, + // event_entry : _dali.type.event_entry + entry : type_entry + ) : HTMLElement + { + return _dali.helpers.template_coin( + "widget-weekview", + "tableview-cell-entry", + { + "color": lib_plankton.color.output_hex( + sources.get( + entry.calendar_id + ).color + ), + "title": class_widget_weekview.event_generate_tooltip( + sources.get( + entry.calendar_id + ).name, + entry.event_object + ), + "name": entry.event_object.name, + "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": (() => { + const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; + switch (access_level) + { + case _dali.type.enum_access_level.none: return "none"; + case _dali.type.enum_access_level.view: return "view"; + case _dali.type.enum_access_level.edit: return "edit"; + case _dali.type.enum_access_level.admin: return "admin"; + } + }) (), + } + ), + "additional_classes": lib_plankton.string.coin( + " access_level-{{access_level}}", + { + "access_level": (() => { + const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; + switch (access_level) + { + case _dali.type.enum_access_level.none: return "none"; + case _dali.type.enum_access_level.view: return "view"; + case _dali.type.enum_access_level.edit: return "edit"; + case _dali.type.enum_access_level.admin: return "admin"; + } + }) (), + } + ), + } + ); + } + + + /** + */ + private add_entry( + event_entry : _dali.type.event_entry + ) : void + { + const dom_entry : HTMLElement = this.create_dom_entry(event_entry); + /** + * @todo insert dom_entry into DOM + */ + this.event_map.set( + event_entry.id, + dom_entry + ); + } + + + /** + */ + private update_entry( + event_id : _dali.type.event_id, + event_entry : _dali.type.event_entry + ) : void + { + const dom_entry_old : HTMLElement = lib_plankton.map.get( + this.event_map, + event_id + ); + /** + * @todo remove dom_entry_old from DOM + */ + const dom_entry_new : HTMLElement = this.create_dom_entry(event_entry); + /** + * @todo insert dom_entry_new into DOM + */ + this.event_map.set( + event_id, + dom_entry_new + ); + } + + + /** + */ + private remove_entry( + event_id : _dali.type.event_id + ) : void + { + const dom_entry : HTMLElement = lib_plankton.map.get( + this.event_map, + event_id + ); + /** + * @todo remove dom_entry from DOM + */ + this.event_map.delete( + event_id + ); + } + + + /** + */ + private sync_events( + events : Array<_dali.type.event_entry> + ) : void + { + const track : Record< + string, + { + external : (null | _dali.type.event_entry); + internal : (null | _dali.type.event_id); + } + > = {}; + events.forEach( + event => { + const key : string = event.id; + if (! (key in track)) track[key] = {"external": null, "internal": null}; + track[key].external = event; + } + ); + lib_plankton.map.dump(this.event_map).forEach( + pair => { + const key : string = pair.key; + if (! (key in track)) track[key] = {"external": null, "internal": null}; + track[key].internal = pair.key; + } + ); + + Object.entries(track).forEach( + ([key, value]) => { + if ( + ! (value.external !== null) + && + ! (value.internal !== null) + ) + { + throw (new Error("impossible!")); + } + else if ( + (value.external !== null) + && + ! (value.internal !== null) + ) + { + this.add_entry(value.external); + } + else if ( + (value.external !== null) + && + (value.internal !== null) + ) + { + this.update_entry(value.internal, value.external); + } + else if ( + ! (value.external !== null) + && + (value.internal !== null) + ) + { + this.remove_entry(value.external.id); + } + else + { + throw (new Error("impossible!")); + } + } + ); + } + + /** * @todo kein "while" */ @@ -341,7 +566,8 @@ namespace _dali.widgets.weekview } > = []; let day : int = 0; - while (true) { + while (true) + { const pit_current : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day( from_pit, day @@ -351,7 +577,8 @@ namespace _dali.widgets.weekview pit_current, to_pit ) - ) { + ) + { day += 1; row.push( { @@ -360,7 +587,8 @@ namespace _dali.widgets.weekview "today": false, // TODO } ); - if (day % 7 === 0) { + if (day % 7 === 0) + { result.rows.push( { "week": ( @@ -375,11 +603,13 @@ namespace _dali.widgets.weekview ); row = []; } - else { + else + { // do nothing } } - else { + else + { break; } } @@ -731,10 +961,12 @@ namespace _dali.widgets.weekview const context : Element = this.container; // controls { - if (! options.update_controls) { + if (! options.update_controls) + { // do nothing } - else { + else + { (context.querySelector(".weekview-control-year > input") as HTMLInputElement).value = year.toFixed(0); (context.querySelector(".weekview-control-week > input") as HTMLInputElement).value = week.toFixed(0); (context.querySelector(".weekview-control-count > input") as HTMLInputElement).value = count.toFixed(0); @@ -760,19 +992,23 @@ namespace _dali.widgets.weekview ); // cells { - if (! await _dali.backend.is_logged_in()) { + if (! await _dali.backend.is_logged_in()) + { // do nothing } - else { + else + { context.querySelectorAll(".weekview-cell-regular").forEach( (element) => { element.addEventListener( "click", (event) => { - if (! (element === event.target)) { + if (! (element === event.target)) + { // do nothing } - else { + else + { const rel : string = element.getAttribute("rel"); const parts : Array = rel.split("-"); const date : lib_plankton.pit.type_date = { @@ -790,10 +1026,12 @@ namespace _dali.widgets.weekview } // events { - if (! await _dali.backend.is_logged_in()) { + if (! await _dali.backend.is_logged_in()) + { // do nothing } - else { + else + { context.querySelectorAll(".weekview-event_entry").forEach( (element) => { element.addEventListener( @@ -864,10 +1102,12 @@ namespace _dali.widgets.weekview const rel : string = element.getAttribute("rel"); const parts : Array = rel.split("/"); const calendar_id_ : _dali.type.calendar_id = parseInt(parts[0]); - if (! (calendar_id === calendar_id_)) { + if (! (calendar_id === calendar_id_)) + { // do nothing } - else { + else + { element.classList.toggle("weekview-cell-hidden"); } } diff --git a/tools/makefile b/tools/makefile index 89727f0..9788fe7 100644 --- a/tools/makefile +++ b/tools/makefile @@ -136,6 +136,7 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/base/helpers.ts \ ${dir_source}/base/types.ts \ ${dir_source}/base/functions.ts \ + ${dir_source}/base/model.ts \ ${dir_source}/resources/conf.ts \ ${dir_source}/resources/backend.ts \ ${dir_source}/widgets/sources/logic.ts \ -- 2.47.3 From c53837ebfe1bdffddd2f7edfee51c9366c08c6c5 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 22:09:49 +0200 Subject: [PATCH 4/9] [upd] plankton --- lib/plankton/plankton.d.ts | 53 ++++++++++++-- lib/plankton/plankton.js | 144 +++++++++++++++++++++++++++++++++++-- 2 files changed, 186 insertions(+), 11 deletions(-) diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 3302bcf..a72512e 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -1,11 +1,11 @@ /** * @author fenris */ -declare type int = number; +type int = number; /** * @author fenris */ -declare type float = number; +type float = number; declare class Buffer { constructor(x: string, modifier?: string); toString(modifier?: string): string; @@ -19,7 +19,7 @@ declare namespace lib_plankton.base { /** * @author fenris */ -declare type type_pseudopointer = { +type type_pseudopointer = { value: type_value; }; /** @@ -1969,7 +1969,7 @@ declare namespace lib_plankton.storage.memory { clear(): Promise; write(key: any, value: any): Promise; delete(key: any): Promise; - read(key: any): Promise; + read(key: any): Promise>; search(term: any): Promise<{ key: string; preview: string; @@ -2693,6 +2693,51 @@ declare namespace lib_plankton.map.collatemap { export function implementation_map(subject: type_subject): type_map; export {}; } +declare namespace lib_plankton.cache { + /** + */ + type type_result = { + retrieved: boolean; + value: type_value; + }; + /** + */ + type type_entry = { + value: type_value; + expiry: (null | float); + }; + /** + */ + type type_subject = lib_plankton.storage.type_chest, void, any, any>; +} +declare namespace lib_plankton.cache { + /** + */ + function make({ "chest": chest, }?: { + chest?: lib_plankton.storage.type_chest, void, any, any>; + }): type_subject; + /** + */ + function init(subject: type_subject): Promise; + /** + */ + function clear(subject: type_subject): Promise; + /** + */ + function invalidate(subject: type_subject, key: string): Promise; + /** + */ + function query(subject: type_subject, key: string, lifetime: (null | float), retrieve: (() => Promise)): Promise>; + /** + * syntactic sugar: if the information, whether the value was retrieved, is irrelevant + */ + function get(subject: type_subject, key: string, lifetime: (null | float), retrieve: (() => Promise)): Promise; + /** + */ + function get_complex(cache: type_subject, group: string, input: type_input, lifetime: (null | float), retrieve: ((input: type_input) => Promise), { "encode_input": encode_input, }?: { + encode_input?: ((input: type_input) => string); + }): Promise; +} declare namespace lib_plankton.complex { /** * @author fenris diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 0a4b816..fa6a73c 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -2151,7 +2151,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -8710,6 +8710,136 @@ var lib_plankton; })(map = lib_plankton.map || (lib_plankton.map = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:cache«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:cache« 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. + +»bacterio-plankton:cache« 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 »bacterio-plankton:cache«. If not, see . + */ +/* +This file is part of »bacterio-plankton:cache«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:cache« 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. + +»bacterio-plankton:cache« 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 »bacterio-plankton:cache«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var cache; + (function (cache_1) { + /** + */ + function make({ "chest": chest = lib_plankton.storage.memory.implementation_chest({}), } = {}) { + return chest; + } + cache_1.make = make; + /** + */ + function init(subject) { + return subject.setup(undefined); + } + cache_1.init = init; + /** + */ + function clear(subject) { + return subject.clear(); + } + cache_1.clear = clear; + /** + */ + function invalidate(subject, key) { + return subject.delete(key); + } + cache_1.invalidate = invalidate; + /** + */ + async function query(subject, key, lifetime, retrieve) { + const now = lib_plankton.base.get_current_timestamp(); + return ((subject.read(key) + .then((entry) => Promise.resolve({ + "found": true, + "entry": entry, + })) + .catch(() => Promise.resolve({ + "found": false, + "entry": null, + }))) + .then((item) => { + if ((!item.found) + || + ((item.entry.expiry !== null) + && + (item.entry.expiry <= now))) { + lib_plankton.log.info("plankton.cache.unknown_or_expired", { + "key": key, + }); + return (retrieve() + .then((value) => (subject.write(key, { + "value": value, + "expiry": ((lifetime === null) + ? + null + : + (now + lifetime)) + }) + .then(() => Promise.resolve({ + "retrieved": true, + "value": value + }))))); + } + else { + lib_plankton.log.info("plankton.cache.known_and_valid", { + "key": key, + }); + return Promise.resolve({ + "retrieved": false, + "value": item.entry.value + }); + } + })); + } + cache_1.query = query; + /** + * syntactic sugar: if the information, whether the value was retrieved, is irrelevant + */ + function get(subject, key, lifetime, retrieve) { + return (query(subject, key, lifetime, retrieve) + .then(result => Promise.resolve(result.value))); + } + cache_1.get = get; + /** + */ + function get_complex(cache, group, input, lifetime, retrieve, { "encode_input": encode_input = (input => JSON.stringify(input)), } = {}) { + return get(cache, (group + "." + encode_input(input)), lifetime, () => retrieve(input)); + } + cache_1.get_complex = get_complex; + })(cache = lib_plankton.cache || (lib_plankton.cache = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:complex«. Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' @@ -9449,6 +9579,12 @@ var lib_plankton; * @author fenris */ class class_relation { + /** + * @author fenris + */ + check(value, reference) { + return this.predicate(value, reference); + } /** * @author fenris */ @@ -9458,12 +9594,6 @@ var lib_plankton; this.name = name; this.predicate = predicate; } - /** - * @author fenris - */ - check(value, reference) { - return this.predicate(value, reference); - } /** * @author fenris */ -- 2.47.3 From 7e1f585f34771aab78d4f40b6a5524c1738fc6ba Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 22:09:57 +0200 Subject: [PATCH 5/9] [upd] plankton --- tools/update-plankton | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/update-plankton b/tools/update-plankton index dad2426..b652c8d 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -14,6 +14,7 @@ modules="${modules} json" modules="${modules} string" modules="${modules} random" modules="${modules} map" +modules="${modules} cache" modules="${modules} color" # modules="${modules} xml" modules="${modules} map" -- 2.47.3 From 4612128134084da9ef55f1cf69b8a1eafd8f9d9d Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 22:10:56 +0200 Subject: [PATCH 6/9] [task-408] [mod] Wochenansich-Steuerelement umgestellt --- source/base/functions.ts | 35 +- source/base/types.ts | 7 +- source/pages/overview/logic.ts | 31 +- source/resources/backend.ts | 67 +- source/widgets/weekview/logic.ts | 1468 +++++++---------- .../widgets/weekview/templates/main.html.tpl | 1 - 6 files changed, 676 insertions(+), 933 deletions(-) diff --git a/source/base/functions.ts b/source/base/functions.ts index 274127d..a4721c9 100644 --- a/source/base/functions.ts +++ b/source/base/functions.ts @@ -1,7 +1,38 @@ namespace _dali { - + /** + */ + export function access_level_encode( + access_level : _dali.type.enum_access_level + ) : ("none" | "view" | "edit" | "admin") + { + switch (access_level) { + case _dali.type.enum_access_level.none: return "none"; + case _dali.type.enum_access_level.view: return "view"; + case _dali.type.enum_access_level.edit: return "edit"; + case _dali.type.enum_access_level.admin: return "admin"; + } + } + + + /** + */ + export function access_level_decode( + representation : /*("none" | "view" | "edit" | "admin")*/string + ) : _dali.type.enum_access_level + { + switch (representation) + { + case "none": return _dali.type.enum_access_level.none; + case "view": return _dali.type.enum_access_level.view; + case "edit": return _dali.type.enum_access_level.edit; + case "admin": return _dali.type.enum_access_level.admin; + default: throw (new Error("invalid access level representation: " + representation)); + } + } + + /** */ export function view_mode_encode( @@ -58,6 +89,6 @@ namespace _dali { return view_mode_decode(mode_descriptor); } - } + } } diff --git a/source/base/types.ts b/source/base/types.ts index e97b1d9..ac35b84 100644 --- a/source/base/types.ts +++ b/source/base/types.ts @@ -42,9 +42,9 @@ namespace _dali.type * extern eingebundene Events kodiert * * @example "local:1234" - * @example "ics:2345" + * @example "ics~2345" */ - export type event_id = string; + export type event_key = string; /** @@ -78,7 +78,8 @@ namespace _dali.type /** */ export type event_entry = { - id : event_id; + id : (null | local_resource_event_id); + key : event_key; object : event_object; }; diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index e798974..94bbb20 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -17,13 +17,6 @@ namespace _dali.pages.overview target_element.querySelector("#overview").classList.toggle("overview-compact", compact); }; - /** - * @todo geschickter bauen (MVC, MVVM, …) - */ - const update = () => { - lib_plankton.zoo_page.reload(); - }; - // exec target_element.innerHTML = await _dali.helpers.template_coin( "overview", @@ -66,6 +59,12 @@ namespace _dali.pages.overview let widget_weekview : _dali.widgets.weekview.class_widget_weekview; let widget_listview : _dali.widgets.listview.class_widget_listview; + /** + * @todo update sources + */ + const update = () => { + widget_weekview.update_entries(); + }; // hint { if (! await _dali.backend.is_logged_in()) @@ -176,6 +175,15 @@ namespace _dali.pages.overview } ); const action_select_event = (calendar_id, access_level, event_id) => { + /* + if (! await _dali.backend.is_logged_in()) + { + // do nothing + } + else + { + } + */ let read_only : boolean; switch (access_level) { @@ -304,6 +312,15 @@ namespace _dali.pages.overview { "action_select_event": action_select_event, "action_select_day": (date) => { + /* + if (! await _dali.backend.is_logged_in()) + { + // do nothing + } + else + { + } + */ (async () => { const widget = new _dali.widgets.event_edit.class_widget_event_edit( { diff --git a/source/resources/backend.ts b/source/resources/backend.ts index 9991f92..c0f6377 100644 --- a/source/resources/backend.ts +++ b/source/resources/backend.ts @@ -14,6 +14,16 @@ namespace _dali.backend /** */ + var _cache : ( + null + | + lib_plankton.cache.type_subject + ); + + + /** + * meant for translation of the API values + */ function access_level_encode( access_level : _dali.type.enum_access_level ) : ("none" | "view" | "edit" | "admin") @@ -28,6 +38,7 @@ namespace _dali.backend /** + * meant for translation of the API values */ function access_level_decode( access_level_encoded : ("none" | "view" | "edit" | "admin") @@ -52,6 +63,14 @@ namespace _dali.backend "corner": "zeitbild", } ); + _cache = lib_plankton.cache.make( + /* + lib_plankton.storage.memory.implementation_chest( + { + } + ) + */ + ); return Promise.resolve(undefined); } @@ -162,19 +181,27 @@ namespace _dali.backend /** + * @todo mneh … */ export async function is_logged_in( ) : Promise { - // return ((await get_session_key()) !== null); - const result : { - logged_in : boolean; - } = await call( - lib_plankton.http.enum_method.get, - "/session/status", - null + return lib_plankton.cache.get( + _cache, + "status", + 5, + async () => { + // return ((await get_session_key()) !== null); + const result : { + logged_in : boolean; + } = await call( + lib_plankton.http.enum_method.get, + "/session/status", + null + ); + return result.logged_in; + } ); - return result.logged_in; } @@ -596,12 +623,20 @@ namespace _dali.backend export async function events( from_pit : lib_plankton.pit.type_pit, to_pit : lib_plankton.pit.type_pit, - options : { + { + "calendar_ids": calendar_ids = null, + } + : + { calendar_ids ?: (null | Array<_dali.type.calendar_id>); - } = {} + } + = + { + } ) : Promise< Array< { + key : _dali.type.event_key; calendar_id : _dali.type.calendar_id; calendar_name : string; hue : float; @@ -612,13 +647,6 @@ namespace _dali.backend > > { - options = Object.assign( - { - "calendar_ids": null, - }, - options - ); - return ( call( lib_plankton.http.enum_method.get, @@ -629,11 +657,11 @@ namespace _dali.backend "to": to_pit, }, ( - (options.calendar_ids === null) + (calendar_ids === null) ? {} : - {"calendar_ids": options.calendar_ids.join(",")} + {"calendar_ids": calendar_ids.join(",")} ) ) ) @@ -642,6 +670,7 @@ namespace _dali.backend data .map( (entry) => ({ + "key": entry.hash, "calendar_id": entry.calendar_id, "calendar_name": entry.calendar_name, "hue": entry.hue, diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index a6265a5..457d9e9 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -4,6 +4,7 @@ namespace _dali.widgets.weekview /** */ type type_entry = { + key : _dali.type.event_key; calendar_id : _dali.type.calendar_id; calendar_name : string; hue : float; @@ -32,24 +33,13 @@ namespace _dali.widgets.weekview { /** + * [dependency] */ private get_entries : type_get_entries; /** - */ - private container : (null | Element); - - - /** - */ - private event_map : lib_plankton.map.type_map< - _dali.type.event_id, - HTMLElement - >; - - - /** + * [hook] */ private action_select_event : ( ( @@ -63,6 +53,7 @@ namespace _dali.widgets.weekview /** + * [hook] */ private action_select_day : ( ( @@ -73,11 +64,55 @@ namespace _dali.widgets.weekview ); + /** + * [state] + */ + private year : int; + + + /** + * [state] + */ + private week : int; + + + /** + * [state] + */ + private count : int; + + + /** + * [state] + */ + private event_map : lib_plankton.map.type_map< + _dali.type.event_key, + { + element : HTMLElement; + hash : string; + } + >; + + + /** + * [state] + */ + private container : (null | Element); + + /** */ public constructor( get_entries : type_get_entries, - options : { + { + "action_select_day": action_select_day = ((date) => {}), + "action_select_event": action_select_event = ((calendar_id, access_level, event_id) => {}), + "initial_year": initial_year = null, + "initial_week": initial_week = null, + "initial_count": initial_count = 5, + } + : + { action_select_event ?: ( ( calendar_id : _dali.type.calendar_id, @@ -94,28 +129,70 @@ namespace _dali.widgets.weekview => void ); - } = {} + initial_year ?: (null | int); + initial_week ?: (null | int); + initial_count ?: int; + } + = + {} ) { - options = Object.assign( - { - "action_select_day": (date) => {}, - "action_select_event": (calendar_id, access_level, event_id) => {}, - }, - options - ); + // dependencies this.get_entries = get_entries; - this.container = null; + + // hooks + this.action_select_day = action_select_day; + this.action_select_event = action_select_event; + + // state + const ywd_now : lib_plankton.pit.type_ywd = lib_plankton.pit.to_ywd(lib_plankton.pit.now()); + this.year = ( + initial_year + ?? + ywd_now.year + ); + this.week = ( + initial_week + ?? + Math.max(0, (ywd_now.week - 1)) + ); + this.count = initial_count; this.event_map = lib_plankton.map.hashmap.implementation_map( lib_plankton.map.hashmap.make< - _dali.type.event_id, - HTMLElement + _dali.type.event_key, + { + element : HTMLElement; + hash : string; + } >( - event_id => event_id + event_key => event_key ) ); - this.action_select_day = options.action_select_day; - this.action_select_event = options.action_select_event; + this.container = null; + } + + + /** + * some kind of checksum for comparing entries + * @todo base64 encode? + * @todo sha256 hash? + */ + private static entry_hash( + entry : type_entry + ) : string + { + return lib_plankton.call.convey( + { + "calendar_id": entry.calendar_id, + "calendar_name": entry.calendar_name, + "hue": Math.floor(entry.hue * 0xFFFF), + "access_level": entry.access_level, + "event_object": entry.event_object, + }, + [ + x => lib_plankton.json.encode(x), + ] + ); } @@ -216,885 +293,479 @@ namespace _dali.widgets.weekview /** */ - private create_dom_entry( - sources : lib_plankton.map.type_map< - _dali.type.calendar_id, - { - name : string; - access_level : _dali.type.enum_access_level; - /** - * @todo replace with hue? - */ - color : lib_plankton.color.type_color; - } - >, - // event_entry : _dali.type.event_entry - entry : type_entry - ) : HTMLElement - { - return _dali.helpers.template_coin( - "widget-weekview", - "tableview-cell-entry", - { - "color": lib_plankton.color.output_hex( - sources.get( - entry.calendar_id - ).color - ), - "title": class_widget_weekview.event_generate_tooltip( - sources.get( - entry.calendar_id - ).name, - entry.event_object - ), - "name": entry.event_object.name, - "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": (() => { - const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) - { - case _dali.type.enum_access_level.none: return "none"; - case _dali.type.enum_access_level.view: return "view"; - case _dali.type.enum_access_level.edit: return "edit"; - case _dali.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - "additional_classes": lib_plankton.string.coin( - " access_level-{{access_level}}", - { - "access_level": (() => { - const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) - { - case _dali.type.enum_access_level.none: return "none"; - case _dali.type.enum_access_level.view: return "view"; - case _dali.type.enum_access_level.edit: return "edit"; - case _dali.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - } - ); - } - - - /** - */ - private add_entry( - event_entry : _dali.type.event_entry - ) : void - { - const dom_entry : HTMLElement = this.create_dom_entry(event_entry); - /** - * @todo insert dom_entry into DOM - */ - this.event_map.set( - event_entry.id, - dom_entry - ); - } - - - /** - */ - private update_entry( - event_id : _dali.type.event_id, - event_entry : _dali.type.event_entry - ) : void - { - const dom_entry_old : HTMLElement = lib_plankton.map.get( - this.event_map, - event_id - ); - /** - * @todo remove dom_entry_old from DOM - */ - const dom_entry_new : HTMLElement = this.create_dom_entry(event_entry); - /** - * @todo insert dom_entry_new into DOM - */ - this.event_map.set( - event_id, - dom_entry_new - ); - } - - - /** - */ - private remove_entry( - event_id : _dali.type.event_id - ) : void - { - const dom_entry : HTMLElement = lib_plankton.map.get( - this.event_map, - event_id - ); - /** - * @todo remove dom_entry from DOM - */ - this.event_map.delete( - event_id - ); - } - - - /** - */ - private sync_events( - events : Array<_dali.type.event_entry> - ) : void - { - const track : Record< - string, - { - external : (null | _dali.type.event_entry); - internal : (null | _dali.type.event_id); - } - > = {}; - events.forEach( - event => { - const key : string = event.id; - if (! (key in track)) track[key] = {"external": null, "internal": null}; - track[key].external = event; - } - ); - lib_plankton.map.dump(this.event_map).forEach( - pair => { - const key : string = pair.key; - if (! (key in track)) track[key] = {"external": null, "internal": null}; - track[key].internal = pair.key; - } - ); - - Object.entries(track).forEach( - ([key, value]) => { - if ( - ! (value.external !== null) - && - ! (value.internal !== null) - ) - { - throw (new Error("impossible!")); - } - else if ( - (value.external !== null) - && - ! (value.internal !== null) - ) - { - this.add_entry(value.external); - } - else if ( - (value.external !== null) - && - (value.internal !== null) - ) - { - this.update_entry(value.internal, value.external); - } - else if ( - ! (value.external !== null) - && - (value.internal !== null) - ) - { - this.remove_entry(value.external.id); - } - else - { - throw (new Error("impossible!")); - } - } - ); - } - - - /** - * @todo kein "while" - */ - private async calendar_view_table_data( - calendar_ids : ( - null - | - Array<_dali.type.calendar_id> - ), - from : { - year : int; - week : int; - }, - to : { - year : int; - week : int; - }, - timezone_shift : int - ) : Promise< + private get_entries_wrapped( { - sources : lib_plankton.map.type_map< - _dali.type.calendar_id, - { - name : string; - access_level : _dali.type.enum_access_level; - hue : float; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _dali.type.calendar_id; - event_id : (null | _dali.type.local_resource_event_id); - event_object : _dali.type.event_object; - } - >; - today : boolean; - } - >; - } - > + "calendar_ids": calendar_ids = null, + "timezone_shift": timezone_shift = 0, } - > + : + { + calendar_ids ?: (null | Array<_dali.type.calendar_id>); + timezone_shift ?: int; + } + = + { + } + ) + : Promise> { - const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); - const from_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( - { - "year": (from as {year : int; week : int}).year, - "week": (from as {year : int; week : int}).week, - "day": 1, - }, - { - "timezone_shift": (timezone_shift as int), - } - ); - const to_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( - { - "year": (to as {year : int; week : int}).year, - "week": (to as {year : int; week : int}).week, - "day": 1, - }, - { - "timezone_shift": (timezone_shift as int), - } - ); - - // prepare - const entries : Array = await this.get_entries( - from_pit, - to_pit, + return this.get_entries( + lib_plankton.pit.from_ywd( + { + "year": this.year, + "week": this.week, + "day": 1, + }, + { + "timezone_shift": timezone_shift, + } + ), + lib_plankton.pit.from_ywd( + { + "year": this.year, + "week": (this.week + this.count), + "day": 1, + }, + { + "timezone_shift": timezone_shift, + } + ), calendar_ids ); - let result : { - sources : lib_plankton.map.type_map< - _dali.type.calendar_id, - { - name : string; - access_level : _dali.type.enum_access_level; - hue : float; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _dali.type.calendar_id; - event_id : (null | _dali.type.local_resource_event_id); - event_object : _dali.type.event_object; - } - >; - today : boolean; - } - >; - } - >; - } = { - "sources": lib_plankton.map.hashmap.implementation_map( - lib_plankton.map.hashmap.make( - x => x.toFixed(0), - { - "pairs": ( - entries - .map( - (entry) => ( - { - "key": entry.calendar_id, - "value": { - "name": entry.calendar_name, - "access_level": entry.access_level, - "hue": entry.hue, - } - } - ) - ) - ) - } - ) - ), - "rows": [], - }; - let row : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _dali.type.calendar_id; - event_id : (null | _dali.type.local_resource_event_id); - event_object : _dali.type.event_object; - } - >; - today : boolean; - } - > = []; - let day : int = 0; - while (true) - { - const pit_current : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day( - from_pit, - day - ); - if ( - lib_plankton.pit.is_before( - pit_current, - to_pit - ) - ) - { - day += 1; - row.push( - { - "pit": pit_current, - "entries": [], - "today": false, // TODO - } - ); - if (day % 7 === 0) - { - result.rows.push( - { - "week": ( - (from as {year : int; week : int}).week - + - Math.floor(day / 7) - - - 1 // TODO - ), - "data": row - } - ); - row = []; - } - else - { - // do nothing - } - } - else - { - break; - } - } - - // fill - { - // events - ( - entries - .forEach( - (entry) => { - const distance_seconds : int = ( - lib_plankton.pit.from_datetime( - /** - * so that events without a start time will be put in the correct box - */ - { - "timezone_shift": entry.event_object.begin.timezone_shift, - "date": entry.event_object.begin.date, - "time": ( - entry.event_object.begin.time - ?? - { - "hour": 12, - "minute": 0, - "second": 0 - } - ), - } - ) - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].entries.push(entry); - } - else { - // do nothing - } - } - ) - ); - // today - { - const distance_seconds : int = ( - now_pit - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].today = true; - } - else { - // do nothing - } - } - } - - return Promise.resolve(result); } /** */ - private async table_rows( - options : { - calendar_ids ?: ( - null - | - Array<_dali.type.calendar_id> - ); - from ?: { - year : int; - week : int; - }; - to ?: { - year : int; - week : int; - }; - timezone_shift ?: int; - action_select ?: ( - ( - calendar_id : _dali.type.calendar_id, - event_id : _dali.type.local_resource_event_id - ) - => - void - ) - } = {} - ) : Promise + private async entry_insert( + entry : type_entry + ) : Promise<(null | HTMLElement)> { - const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); - options = Object.assign( + const selector : string = lib_plankton.string.coin( + ".weekview-cell[rel=\"{{rel}}\"] > .weekview-events", { - "calendar_ids": null, - "from": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, -1), - lib_plankton.pit.to_ywd, - x => ({"year": x.year, "week": x.week}), - ] - ), - "to": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, +4), - lib_plankton.pit.to_ywd, - x => ({"year": x.year, "week": x.week}), - ] - ), - "timezone_shift": 0, - }, - options - ); - const stuff : { - sources : lib_plankton.map.type_map< - _dali.type.calendar_id, - { - name : string; - access_level : _dali.type.enum_access_level; - hue : float; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _dali.type.calendar_id; - event_id : (null | _dali.type.local_resource_event_id); - event_object : _dali.type.event_object; - } - >; - today : boolean; - } - >; - } - >; - } = await this.calendar_view_table_data( - options.calendar_ids, - options.from, - options.to, - options.timezone_shift - ); - const sources : lib_plankton.map.type_map< - _dali.type.calendar_id, - { - name : string; - access_level : _dali.type.enum_access_level; - color : lib_plankton.color.type_color; + "rel": lib_plankton.pit.date_format(entry.event_object.begin.date), } - > = lib_plankton.map.hashmap.implementation_map( - lib_plankton.map.hashmap.make( - (x => x.toFixed(0)), - { - "pairs": ( - lib_plankton.map.dump( - stuff.sources - ) - .map( - (pair) => ({ - "key": pair.key, - "value": { - "name": pair.value.name, - "access_level": pair.value.access_level, - "color": lib_plankton.color.make_hsv( - { - "hue": pair.value.hue, - "saturation": 0.375, - "value": 0.375, - } - ), - } - }) - ) - ) - } - ) ); - return ( - await _dali.helpers.promise_row( - stuff.rows - .map( - (row) => async () => _dali.helpers.template_coin( - "widget-weekview", - "tableview-row", + const dom_cell = this.container.querySelector(selector); + if (dom_cell === null) + { + console.warn("entry out of scope"); + return null; + } + else + { + let dom_dummy : HTMLElement = document.createElement("div"); + dom_dummy.innerHTML = await _dali.helpers.template_coin( + "widget-weekview", + "tableview-cell-entry", + { + "color": lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": entry.hue, + /** + * @todo as constant + */ + "saturation": 0.375, + /** + * @todo as constant + */ + "value": 0.375, + } + ) + ), + "title": class_widget_weekview.event_generate_tooltip( + entry.calendar_name, + entry.event_object + ), + "name": entry.event_object.name, + "rel": lib_plankton.string.coin( + "{{calendar_id}}/{{event_id}}/{{access_level}}", { - "week": row.week.toFixed(0).padStart(2, "0"), - "cells": ( - await _dali.helpers.promise_row( - row.data - .map( - (cell) => async () => _dali.helpers.template_coin( - "widget-weekview", - "tableview-cell", - { - "extra_classes": ( - [""] - .concat(cell.today ? ["weekview-cell-today"] : []) - .join(" ") - ), - "title": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "day": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "rel": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime_ce, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ) - ] - ), - "entries": ( - await _dali.helpers.promise_row( - cell.entries - .map( - (entry) => () => _dali.helpers.template_coin( - "widget-weekview", - "tableview-cell-entry", - { - "color": lib_plankton.color.output_hex( - sources.get( - entry.calendar_id - ).color - ), - "title": class_widget_weekview.event_generate_tooltip( - sources.get( - entry.calendar_id - ).name, - entry.event_object - ), - "name": entry.event_object.name, - "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": (() => { - const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) { - case _dali.type.enum_access_level.none: return "none"; - case _dali.type.enum_access_level.view: return "view"; - case _dali.type.enum_access_level.edit: return "edit"; - case _dali.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - "additional_classes": lib_plankton.string.coin( - " access_level-{{access_level}}", - { - "access_level": (() => { - const access_level : _dali.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) { - case _dali.type.enum_access_level.none: return "none"; - case _dali.type.enum_access_level.view: return "view"; - case _dali.type.enum_access_level.edit: return "edit"; - case _dali.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - } - ) - ) - ) - ).join(""), - } - ) - ) - ) - ).join(""), + "calendar_id": entry.calendar_id.toFixed(0), + "event_id": ( + (entry.event_id === null) + ? + "-" + : + entry.event_id.toFixed(0) + ), + "access_level": _dali.access_level_encode(entry.access_level), } - ) - ) - ) - ).join(""); + ), + "additional_classes": lib_plankton.string.coin( + " access_level-{{access_level}}", + { + "access_level": _dali.access_level_encode(entry.access_level), + } + ), + } + ); + const dom_entry : HTMLElement = dom_dummy.querySelector(".weekview-event_entry"); + + // listener + dom_entry.addEventListener( + "click", + (event) => { + const rel : string = dom_entry.getAttribute("rel"); + const parts : Array = rel.split("/"); + const calendar_id : _dali.type.calendar_id = parseInt(parts[0]); + const event_id : (null | _dali.type.local_resource_event_id) = ( + (parts[1] === "-") + ? + null + : + parseInt(parts[1]) + ); + const access_level : _dali.type.enum_access_level = _dali.access_level_decode(parts[2]); + this.action_select_event( + calendar_id, + access_level, + event_id + ); + } + ); + + // emplace + dom_cell.appendChild(dom_entry); + + return dom_entry; + } } /** */ - private async update( - year : int, - week : int, - count : int, - options : { - update_controls ?: boolean; - } = {} + private async entry_add( + entry : type_entry ) : Promise { - options = Object.assign( - { - "update_controls": true, - }, - options - ); - const context : Element = this.container; - // controls + const dom_entry : (null | HTMLElement) = await this.entry_insert(entry); + if (dom_entry === null) { - if (! options.update_controls) - { - // do nothing - } - else - { - (context.querySelector(".weekview-control-year > input") as HTMLInputElement).value = year.toFixed(0); - (context.querySelector(".weekview-control-week > input") as HTMLInputElement).value = week.toFixed(0); - (context.querySelector(".weekview-control-count > input") as HTMLInputElement).value = count.toFixed(0); - } + // do nothing } - // table + else { - context.querySelector(".weekview-table tbody").innerHTML = await this.table_rows( + this.event_map.set( + entry.key, { - "calendar_ids": null, - // TODO - "from": { - "year": year, - "week": week - }, - // TODO - "to": { - "year": year, - "week": (week + count) - }, - "timezone_shift": /*conf.timezone_shift*/0, + "element": dom_entry, + "hash": class_widget_weekview.entry_hash(entry), } ); - // cells - { - if (! await _dali.backend.is_logged_in()) - { - // do nothing - } - else - { - context.querySelectorAll(".weekview-cell-regular").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - if (! (element === event.target)) - { - // do nothing - } - else - { - const rel : string = element.getAttribute("rel"); - const parts : Array = rel.split("-"); - const date : lib_plankton.pit.type_date = { - "year": parseInt(parts[0]), - "month": parseInt(parts[1]), - "day": parseInt(parts[2]), - }; - this.action_select_day(date); - } - } - ); - } - ); - } - } - // events - { - if (! await _dali.backend.is_logged_in()) - { - // do nothing - } - else - { - context.querySelectorAll(".weekview-event_entry").forEach( - (element) => { - element.addEventListener( - "click", - () => { - const rel : string = element.getAttribute("rel"); - const parts : Array = rel.split("/"); - const calendar_id : _dali.type.calendar_id = parseInt(parts[0]); - const event_id : (null | _dali.type.local_resource_event_id) = ( - (parts[1] === "-") - ? - null - : - parseInt(parts[1]) - ); - const access_level : _dali.type.enum_access_level = (() => { - switch (parts[2]) { - case "none": return _dali.type.enum_access_level.none; - case "view": return _dali.type.enum_access_level.view; - case "edit": return _dali.type.enum_access_level.edit; - case "admin": return _dali.type.enum_access_level.admin; - } - }) (); - this.action_select_event( - calendar_id, - access_level, - event_id - ); - } - ); - } - ); - } - } } - return Promise.resolve(undefined); } /** */ - private react_on_control_change( - dom_context : Element - ) : void + private async entry_update( + key : _dali.type.event_key, + entry : type_entry + ) : Promise { - const year : int = parseInt((dom_context.querySelector(".weekview-control-year > input") as HTMLInputElement).value); - const week : int = parseInt((dom_context.querySelector(".weekview-control-week > input") as HTMLInputElement).value); - const count : int = parseInt((dom_context.querySelector(".weekview-control-count > input") as HTMLInputElement).value); - this.update( - year, - week, - count, + if (! this.event_map.has(key)) + { + console.warn("event missing: " + key); + } + else + { + const value = this.event_map.get(key); + const hash_old : string = value.hash; + const hash_new : string = class_widget_weekview.entry_hash(entry); + if (hash_old === hash_new) { - "update_controls": false, + // do nothing + // console.info("nothing to update", {"key": key, "entry": entry, "element": value.element}); } + else + { + const dom_entry_old : HTMLElement = value.element; + dom_entry_old.remove(); + const dom_entry_new : (null | HTMLElement) = await this.entry_insert(entry); + if (dom_entry_new === null) + { + // do nothing + } + else + { + this.event_map.set( + entry.key, + { + "element": dom_entry_new, + "hash": hash_new, + } + ); + } + } + } + } + + + /** + */ + private async entry_remove( + key : _dali.type.event_key + ) : Promise + { + if (! this.event_map.has(key)) + { + // do nothing + // console.warn("not in map", {"key": key, "map": lib_plankton.map.dump(this.event_map)}); + } + else + { + const value = this.event_map.get( + key + ); + this.event_map.delete( + key + ); + value.element.remove(); + } + } + + + /** + */ + public async update_entries( + ) : Promise + { + const entries : Array = await this.get_entries_wrapped( ); + + const contrast = lib_plankton.list.contrast< + any, + type_entry + >( + lib_plankton.map.dump(this.event_map), + pair => pair.key, + entries, + event => event.key + ); + await Promise.all( + [] + // remove + .concat( + contrast.only_left.map( + ({"key": key, "left": left}) => this.entry_remove(key) + ) + ) + // update + .concat( + contrast.both.map( + ({"key": key, "left": left, "right": right}) => this.entry_update(key, right) + ) + ) + // add + .concat( + contrast.only_right.map( + ({"key": key, "right": right}) => this.entry_add(right) + ) + ) + ); + } + + + /** + */ + private async update_controls( + ) : Promise + { + const context : Element = this.container; + (context.querySelector(".weekview-control-year > input") as HTMLInputElement).value = this.year.toFixed(0); + (context.querySelector(".weekview-control-week > input") as HTMLInputElement).value = this.week.toFixed(0); + (context.querySelector(".weekview-control-count > input") as HTMLInputElement).value = this.count.toFixed(0); + } + + + /** + */ + private async update_table( + ) : Promise + { + /** + * @todo avoid? + */ + lib_plankton.map.clear(this.event_map); + const context : Element = this.container; + // structure + { + /** + * @todo als Variable? + */ + const timezone_shift : int = 0; + const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); + const today_begin_pit : lib_plankton.pit.type_pit = lib_plankton.pit.trunc_day(now_pit); + const today_end_pit : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day(today_begin_pit, 1); + const row_data : Array< + { + week : int; + data : Array< + { + pit : lib_plankton.pit.type_pit; + today : boolean; + } + >; + } + > = ( + lib_plankton.list.sequence(this.count) + .map( + offset => { + const week : int = (this.week + offset); + return { + "week": week, + "data": ( + lib_plankton.list.sequence(7) + .map( + day => { + const day_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( + { + "year": this.year, + "week": week, + "day": (day + 1), + }, + { + "timezone_shift": timezone_shift, + } + ); + return { + "pit": day_pit, + "today": lib_plankton.pit.is_between( + day_pit, + today_begin_pit, + today_end_pit + ), + }; + } + ) + ), + }; + } + ) + ); + context.querySelector(".weekview-table tbody").innerHTML = ( + await _dali.helpers.promise_row( + row_data + .map( + (row) => async () => _dali.helpers.template_coin( + "widget-weekview", + "tableview-row", + { + "week": row.week.toFixed(0).padStart(2, "0"), + "cells": ( + await _dali.helpers.promise_row( + row.data + .map( + (cell) => async () => _dali.helpers.template_coin( + "widget-weekview", + "tableview-cell", + { + "extra_classes": ( + [""] + .concat(cell.today ? ["weekview-cell-today"] : []) + .join(" ") + ), + "title": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] + ), + "day": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] + ), + "rel": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime_ce, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ) + ] + ), + "entries": "" + } + ) + ) + ) + ).join(""), + } + ) + ) + ) + ).join(""); + } + // listeners + { + context.querySelectorAll(".weekview-cell-regular").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + if (! (element === event.target)) + { + // do nothing + } + else + { + const rel : string = element.getAttribute("rel"); + const parts : Array = rel.split("-"); + const date : lib_plankton.pit.type_date = { + "year": parseInt(parts[0]), + "month": parseInt(parts[1]), + "day": parseInt(parts[2]), + }; + this.action_select_day(date); + } + } + ); + } + ); + } } /** */ public toggle_visibility( - calendar_id : _dali.type.calendar_id + calendar_id : _dali.type.calendar_id, + { + "mode": mode = null, + } + : + { + mode ?: (null | boolean); + } + = + { + } ) : void { this.container.querySelectorAll(".weekview-event_entry").forEach( @@ -1108,7 +779,7 @@ namespace _dali.widgets.weekview } else { - element.classList.toggle("weekview-cell-hidden"); + element.classList.toggle("weekview-cell-hidden", mode ?? undefined); } } ); @@ -1142,48 +813,43 @@ namespace _dali.widgets.weekview this.container = target_element.querySelector(".weekview"); // controls { - target_element.querySelector(".weekview-control-apply").addEventListener( - "click", - (event) => { - event.preventDefault(); - this.react_on_control_change(target_element); - } - ); - if (false) - { - [ - "year", - "week", - "count", - ].forEach( - (name) => { - const selector : string = (".weekview-control-" + name + " > input"); - (target_element.querySelector(selector) as HTMLInputElement).addEventListener( - "change", - (event) => { - event.preventDefault(); - this.react_on_control_change(target_element); - } - ); - } - ); - } - } - // table - { - const ywd_now : lib_plankton.pit.type_ywd = lib_plankton.pit.to_ywd(lib_plankton.pit.now()); - let year : int = ywd_now.year; - let week : int = Math.max(0, (ywd_now.week - 1)); - let count : int = 5; - await this.update( - year, - week, - count, + [ { - "update_controls": true, + "name": "year", + "transform": parseInt, + "write": x => {this.year = x;} + }, + { + "name": "week", + "transform": parseInt, + "write": x => {this.week = x;} + }, + { + "name": "count", + "transform": parseInt, + "write": x => {this.count = x;} + }, + ].forEach( + (entry) => { + const selector : string = (".weekview-control-" + entry.name + " > input"); + const element : HTMLInputElement = (target_element.querySelector(selector) as HTMLInputElement); + element.addEventListener( + "change", + async (event) => { + event.preventDefault(); + const value : int = entry.transform(element.value); + entry.write(value); + await this.update_table(); + await this.update_entries(); + } + ); } ); } + await this.update_controls(); + await this.update_table(); + await this.update_entries(); + return Promise.resolve(undefined); } diff --git a/source/widgets/weekview/templates/main.html.tpl b/source/widgets/weekview/templates/main.html.tpl index 0ebb5f0..30a6ee5 100644 --- a/source/widgets/weekview/templates/main.html.tpl +++ b/source/widgets/weekview/templates/main.html.tpl @@ -12,7 +12,6 @@ {{label_control_count}} -
-- 2.47.3 From c6d868b2438054cb2d25aa31c0c1696ea88ce6aa Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 23:04:31 +0200 Subject: [PATCH 7/9] [task-408] [mod] Quellen-Steuerelement umgestellt --- source/data/localization/deu.loc.json | 1 + source/data/localization/eng.loc.json | 1 + source/pages/overview/logic.ts | 22 +- source/style/main.css | 6 +- source/style/widget-sources.css | 6 +- source/widgets/sources/logic.ts | 326 +++++++++++------- .../widgets/sources/templates/main.html.tpl | 9 +- 7 files changed, 233 insertions(+), 138 deletions(-) diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 52bdc5b..dfc7be8 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -55,6 +55,7 @@ "widget.event_edit.actions.add": "anlegen", "widget.event_edit.actions.change": "ändern", "widget.event_edit.actions.remove": "löschen", + "widget.sources.create": "anlegen", "page.login.title": "Anmelden", "page.login.internal.name": "Name", "page.login.internal.password": "Kennwort", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 023e8d2..4daaa92 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -55,6 +55,7 @@ "widget.event_edit.actions.add": "add", "widget.event_edit.actions.change": "change", "widget.event_edit.actions.remove": "delete", + "widget.sources.create": "create", "page.login.title": "Login", "page.login.internal.name": "name", "page.login.internal.password": "password", diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index 94bbb20..7a6aa6c 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -57,13 +57,15 @@ namespace _dali.pages.overview await widget_mode_switcher.load(target_element.querySelector("#overview-mode")); } + let widget_sources : _dali.widgets.sources.class_widget_sources; let widget_weekview : _dali.widgets.weekview.class_widget_weekview; let widget_listview : _dali.widgets.listview.class_widget_listview; /** * @todo update sources */ - const update = () => { - widget_weekview.update_entries(); + const update = async () => { + await widget_weekview.update_entries(); + await widget_sources.update(); }; // hint { @@ -78,17 +80,8 @@ namespace _dali.pages.overview } // sources { - const data : Array< - { - id : _dali.type.calendar_id; - name : string; - hue : float; - access_level : _dali.type.enum_access_level; - } - > = await _dali.backend.calendar_list( - ); - const widget_sources = new _dali.widgets.sources.class_widget_sources( - data, + widget_sources = new _dali.widgets.sources.class_widget_sources( + _dali.backend.calendar_list, { "action_open": (entry) => { let read_only : boolean; @@ -161,6 +154,9 @@ namespace _dali.pages.overview widget_weekview.toggle_visibility(entry.id); widget_listview.toggle_visibility(entry.id); }, + "action_create": () => { + console.warn("not implemented: calendar_add widget"); + }, } ); await widget_sources.load(target_element.querySelector("#overview-pane-left")); diff --git a/source/style/main.css b/source/style/main.css index ea384f0..2f85e01 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -89,12 +89,14 @@ nav a:hover a { text-decoration: none; - color: hsl(var(--hue), 50%, 50%); + color: hsl(var(--hue), 0%, 87.5%); } a:hover { - color: hsl(var(--hue), 50%, 75%); + color: hsl(var(--hue), 0%, 100%); + border-bottom: 2px solid hsl(0, 0%, 100%); + transition: 1s ease color; } input,select,textarea diff --git a/source/style/widget-sources.css b/source/style/widget-sources.css index bfcb618..efc6e46 100644 --- a/source/style/widget-sources.css +++ b/source/style/widget-sources.css @@ -1,9 +1,13 @@ .sources +{ + font-size: 0.75em; +} + +.sources-entries { margin: 0; padding: 0; list-style-type: none; - font-size: 0.75em; } .sources-entry diff --git a/source/widgets/sources/logic.ts b/source/widgets/sources/logic.ts index 01c082c..53a4931 100644 --- a/source/widgets/sources/logic.ts +++ b/source/widgets/sources/logic.ts @@ -17,53 +17,230 @@ namespace _dali.widgets.sources { /** + * [dependency] */ - private keys : Array; - - - /** - */ - private data : Record; + private get_entries : (() => Promise>); /** + * [hook] */ private action_open : ((entry : type_entry) => void); /** + * [hook] */ private action_toggle_visibility : ((entry : type_entry) => void); + /** + * [hook] + */ + private action_create : (() => void); + + + /** + * [state] + */ + private container : (null | Element); + + /** */ public constructor( - entries : Array, - options : { + get_entries : (() => Promise>), + { + "action_open": action_open = ((calendar_id) => {}), + "action_toggle_visibility": action_toggle_visibility = ((calendar_id) => {}), + "action_create": action_create = (() => {}), + } + : + { action_open ?: ((entry : type_entry) => void); action_toggle_visibility ?: ((entry : type_entry) => void); - } = {} + action_create ?: (() => void); + } + = + { + } ) { - options = Object.assign( - { - "action_open": (calendar_id) => {}, - "action_toggle_visibility": (calendar_id) => {}, - }, - options + // dependencies + this.get_entries = get_entries; + + // hooks + this.action_open = action_open; + this.action_toggle_visibility = action_toggle_visibility; + this.action_create = action_create; + + // state + this.container = null; + } + + + /** + */ + private static id_encode( + id : _dali.type.calendar_id + ) + : string + { + return id.toFixed(0); + } + + + /** + */ + private static id_decode( + representation : string + ) + : _dali.type.calendar_id + { + return parseInt(representation); + } + + + /** + */ + public async update( + ) + : Promise + { + 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, + }) + ) + ), + } + ) ); - 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; + // structure + { + this.container.innerHTML = await _dali.helpers.template_coin( + "widget-sources", + "main", + { + "label_create": lib_plankton.translate.get("widget.sources.create"), + "entries": ( + ( + await _dali.helpers.promise_row( + lib_plankton.map.dump(data) + .map( + (pair) => () => { + return _dali.helpers.template_coin( + "widget-sources", + "entry", + { + "name": pair.value.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 + // TODO centralize + "color_head": lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": pair.value.hue, + /** + * @todo const and outsource + */ + "saturation": 0.375, + /** + * @todo const and outsource + */ + "value": 0.375, + } + ), + ), + "color_body": lib_plankton.color.output_hex( + lib_plankton.color.make_hsv( + { + "hue": pair.value.hue, + /** + * @todo const and outsource + */ + "saturation": 0.375, + /** + * @todo const and outsource + */ + "value": 0.25, + } + ), + ), + "rel": class_widget_sources.id_encode(pair.key), + } + ); + } + ) + ) + ) + .join("") + ), + } + ); + } + // listeners + { + this.container.querySelector(".sources-create").addEventListener( + "click", + (event) => { + event.preventDefault(); + this.action_create(); + } + ); + this.container.querySelectorAll(".sources-entry-head").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + element.parentElement.classList.toggle("sources-entry-open"); + } + ); + } + ); + this.container.querySelectorAll(".sources-entry-toggle").forEach( + (element) => { + element.addEventListener( + "click", + () => { + const key_encoded : string = element.parentElement.parentElement.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.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-edit").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + const key_encoded : string = element.parentElement.parentElement.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); + this.action_open(entry); + } + ); + } + ); + } } @@ -72,100 +249,11 @@ namespace _dali.widgets.sources */ public async load( target_element : Element - ) : Promise + ) + : Promise { - target_element.innerHTML = await _dali.helpers.template_coin( - "widget-sources", - "main", - { - "entries": ( - ( - await _dali.helpers.promise_row( - this.keys - .map( - (key) => () => { - const entry : type_entry = this.data[key]; - return _dali.helpers.template_coin( - "widget-sources", - "entry", - { - "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 - // TODO centralize - "color_head": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - "saturation": 0.375, - "value": 0.375, - } - ), - ), - "color_body": lib_plankton.color.output_hex( - lib_plankton.color.make_hsv( - { - "hue": entry.hue, - "saturation": 0.375, - "value": 0.25, - } - ), - ), - "rel": key, - } - ); - } - ) - ) - ) - .join("") - ), - } - ); - target_element.querySelectorAll(".sources-entry-head").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - element.parentElement.classList.toggle("sources-entry-open"); - } - ); - } - ); - target_element.querySelectorAll(".sources-entry-toggle").forEach( - (element) => { - element.addEventListener( - "click", - () => { - 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); - } - ); - } - ); - target_element.querySelectorAll(".sources-entry-edit").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel"); - const entry : type_entry = this.data[key]; - this.action_open(entry); - } - ); - } - ); - return Promise.resolve(undefined); + this.container = target_element; + await this.update(); } } diff --git a/source/widgets/sources/templates/main.html.tpl b/source/widgets/sources/templates/main.html.tpl index 3f9a9a7..ba432fd 100644 --- a/source/widgets/sources/templates/main.html.tpl +++ b/source/widgets/sources/templates/main.html.tpl @@ -1,3 +1,6 @@ -
    - {{entries}} -
+
+
    + {{entries}} +
+ {{label_create}} +
-- 2.47.3 From c6f3d9fd578374d8eb685078f9040104cb129246 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 23:18:30 +0200 Subject: [PATCH 8/9] =?UTF-8?q?[task-408]=20[mod]=20Kalender-Hinzuf=C3=BCg?= =?UTF-8?q?en-Seite=20entfernt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/data/localization/deu.loc.json | 1 + source/data/localization/eng.loc.json | 1 + source/main.ts | 12 - source/pages/calendar_add/logic.ts | 228 ------------------ .../calendar_add/templates/default.html.tpl | 5 - source/pages/calendar_edit/logic.ts | 68 ------ .../calendar_edit/templates/default.html.tpl | 5 - source/pages/overview/logic.ts | 48 +++- source/widgets/calendar_edit/logic.ts | 24 ++ tools/makefile | 18 -- 10 files changed, 71 insertions(+), 339 deletions(-) delete mode 100644 source/pages/calendar_add/logic.ts delete mode 100644 source/pages/calendar_add/templates/default.html.tpl delete mode 100644 source/pages/calendar_edit/logic.ts delete mode 100644 source/pages/calendar_edit/templates/default.html.tpl diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index dfc7be8..957d735 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -50,6 +50,7 @@ "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", "widget.weekview.controls.apply": "Laden", + "widget.calendar_edit.actions.add": "anlegen", "widget.calendar_edit.actions.change": "ändern", "widget.calendar_edit.actions.remove": "löschen", "widget.event_edit.actions.add": "anlegen", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 4daaa92..ab7151c 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -50,6 +50,7 @@ "widget.weekview.controls.week": "Week", "widget.weekview.controls.count": "Count", "widget.weekview.controls.apply": "Load", + "widget.calendar_edit.actions.add": "add", "widget.calendar_edit.actions.change": "change", "widget.calendar_edit.actions.remove": "delete", "widget.event_edit.actions.add": "add", diff --git a/source/main.ts b/source/main.ts index 6998722..df3090d 100644 --- a/source/main.ts +++ b/source/main.ts @@ -82,23 +82,11 @@ namespace _dali "label": lib_plankton.translate.get("page.overview.title"), "groups": ["logged_out", "logged_in"], }, - { - "location": {"name": "calendar_add", "parameters": {}}, - "label": lib_plankton.translate.get("page.calendar_add.title"), - "groups": ["logged_in"], - }, { "location": {"name": "caldav", "parameters": {}}, "label": lib_plankton.translate.get("page.caldav.title"), "groups": ["logged_in"], }, - /* - { - "location": {"name": "event_add", "parameters": {}}, - "label": lib_plankton.translate.get("page.event_add.title"), - "groups": ["logged_in"], - } - */ { "location": {"name": "logout", "parameters": {}}, "label": lib_plankton.translate.get("page.logout.title"), diff --git a/source/pages/calendar_add/logic.ts b/source/pages/calendar_add/logic.ts deleted file mode 100644 index 7438bb4..0000000 --- a/source/pages/calendar_add/logic.ts +++ /dev/null @@ -1,228 +0,0 @@ -namespace _dali.pages -{ - - /** - */ - lib_plankton.zoo_page.register( - "calendar_add", - async (parameters, target_element) => { - target_element.innerHTML = ""; - target_element.innerHTML = await _dali.helpers.template_coin( - "calendar_add", - "default", - { - "label": lib_plankton.translate.get("page.calendar_add.title") - } - ); - const form : lib_plankton.zoo_form.class_form< - { - name : string; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - resource_kind : string; - hue : (null | float); - }, - { - name : string; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - resource_kind : string; - hue : (null | float); - } - > = new lib_plankton.zoo_form.class_form< - { - name : string; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - resource_kind : string; - hue : (null | float); - }, - { - name : string; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - resource_kind : string; - hue : (null | float); - } - >( - (value) => value, - (raw) => raw, - new lib_plankton.zoo_input.class_input_group( - [ - { - "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", - "input": await _dali.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"), - "procedure": async (get_value, get_representation) => { - const value : any = await get_value(); - const calendar_object : _dali.type.calendar_object = { - "name": value.name, - "access": { - "public": value.access.public, - "default_level": value.access.default_level, - "attributed": value.access.attributed, - }, - "resource": (() => { - switch (value.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: " + value.resource_kind)); - break; - } - } - }) (), - "hue": value.hue, - }; - try - { - await _dali.backend.calendar_add( - calendar_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("#calendar_add_form")); - await form.input_write( - { - "name": "", - "access": { - "public": false, - "default_level": _dali.type.enum_access_level.view, - "attributed": lib_plankton.map.hashmap.implementation_map< - _dali.type.user_id, - _dali.type.enum_access_level - >( - lib_plankton.map.hashmap.make< - _dali.type.user_id, - _dali.type.enum_access_level - >( - user_id => user_id.toFixed(0), - ) - ), - }, - "resource_kind": "local", - "hue": lib_plankton.random.generate_unit(), - } - ); - return Promise.resolve(undefined); - } - ); - -} diff --git a/source/pages/calendar_add/templates/default.html.tpl b/source/pages/calendar_add/templates/default.html.tpl deleted file mode 100644 index 3b573e7..0000000 --- a/source/pages/calendar_add/templates/default.html.tpl +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{label}}

-
-
-
diff --git a/source/pages/calendar_edit/logic.ts b/source/pages/calendar_edit/logic.ts deleted file mode 100644 index 8221f13..0000000 --- a/source/pages/calendar_edit/logic.ts +++ /dev/null @@ -1,68 +0,0 @@ -namespace _dali.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 _dali.helpers.template_coin( - "calendar_edit", - "default", - { - "label": lib_plankton.translate.get("page.calendar_edit.title.regular") - } - ); - const calendar_object : _dali.type.calendar_object = await _dali.backend.calendar_get( - calendar_id - ); - const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( - { - "read_only": read_only, - "action_change": (data) => { - _dali.backend.calendar_change( - calendar_id, - data - ) - .then( - () => { - lib_plankton.zoo_page.set( - { - "name": "overview", - "parameters": {} - } - ); - } - ); - }, - "action_remove": (data) => { - _dali.backend.calendar_remove( - calendar_id - ) - .then( - () => { - lib_plankton.zoo_page.set( - { - "name": "overview", - "parameters": {} - } - ); - } - ); - }, - "initial_value": { - "name": calendar_object.name, - "hue": calendar_object.hue, - "access": calendar_object.access, - }, - } - ); - await widget.load(document.querySelector("#calendar_edit_form")); - return Promise.resolve(undefined); - } - ); - -} diff --git a/source/pages/calendar_edit/templates/default.html.tpl b/source/pages/calendar_edit/templates/default.html.tpl deleted file mode 100644 index 62d2f1a..0000000 --- a/source/pages/calendar_edit/templates/default.html.tpl +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{label}}

-
-
-
diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index 7a6aa6c..d2f2b15 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -83,6 +83,51 @@ namespace _dali.pages.overview widget_sources = new _dali.widgets.sources.class_widget_sources( _dali.backend.calendar_list, { + "action_create": () => { + (async () => { + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + { + "read_only": false, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_add": (data) => { + _dali.backend.calendar_add( + { + "name": data.name, + "hue": data.hue, + "access": data.access, + "resource": { + "kind": "local", + "data": { + "events": [], + } + } + } + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.calendar_add_error", + {"details": String(reason)} + ); + } + ); + }, + "initial_value": null, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); + }, "action_open": (entry) => { let read_only : boolean; switch (entry.access_level) @@ -154,9 +199,6 @@ namespace _dali.pages.overview widget_weekview.toggle_visibility(entry.id); widget_listview.toggle_visibility(entry.id); }, - "action_create": () => { - console.warn("not implemented: calendar_add widget"); - }, } ); await widget_sources.load(target_element.querySelector("#overview-pane-left")); diff --git a/source/widgets/calendar_edit/logic.ts b/source/widgets/calendar_edit/logic.ts index ac45f84..f4327eb 100644 --- a/source/widgets/calendar_edit/logic.ts +++ b/source/widgets/calendar_edit/logic.ts @@ -33,6 +33,11 @@ namespace _dali.widgets.calendar_edit private action_cancel ?: (null | (() => void)); + /** + */ + private action_add ?: (null | ((value : type_value) => void)); + + /** */ private action_change ?: (null | ((value : type_value) => void)); @@ -54,6 +59,7 @@ namespace _dali.widgets.calendar_edit { "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, "initial_value": initial_value = null, @@ -62,6 +68,7 @@ namespace _dali.widgets.calendar_edit { 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)); initial_value ?: (null | type_value); @@ -73,6 +80,7 @@ namespace _dali.widgets.calendar_edit { 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; this.initial_value = initial_value; @@ -150,6 +158,22 @@ namespace _dali.widgets.calendar_edit : [] ) + // 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 : type_value = await get_value(); + this.action_add(value); + } + }, + ] + : + [] + ) // change .concat( ((! this.read_only) && (! (this.action_change === null))) diff --git a/tools/makefile b/tools/makefile index 9788fe7..2ca4fa3 100644 --- a/tools/makefile +++ b/tools/makefile @@ -39,8 +39,6 @@ templates: \ templates-widgets-calendar_edit \ templates-widgets-event_edit \ templates-pages-caldav \ - templates-pages-calendar_add \ - templates-pages-calendar_edit \ templates-pages-overview \ templates-pages-login @@ -93,20 +91,6 @@ templates-pages-caldav: \ @ ${cmd_mkdir} ${dir_build}/templates/caldav @ ${cmd_cp} -r -u -v ${dir_source}/pages/caldav/templates/* ${dir_build}/templates/caldav/ -.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-overview templates-pages-overview: \ $(wildcard ${dir_source}/pages/overview/templates/*) @@ -150,8 +134,6 @@ ${dir_temp}/logic-unlinked.js: \ ${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/overview/logic.ts \ ${dir_source}/main.ts @ ${cmd_log} "logic | compile …" -- 2.47.3 From 1990c047c2cec79d47098dfce2b52627e911832c Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 14 Oct 2025 23:34:06 +0200 Subject: [PATCH 9/9] [task-408] [mod] loc --- source/data/localization/deu.loc.json | 2 +- source/data/localization/eng.loc.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 957d735..81f9572 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -50,7 +50,7 @@ "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", "widget.weekview.controls.apply": "Laden", - "widget.calendar_edit.actions.add": "anlegen", + "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", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index ab7151c..63bee86 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -50,7 +50,7 @@ "widget.weekview.controls.week": "Week", "widget.weekview.controls.count": "Count", "widget.weekview.controls.apply": "Load", - "widget.calendar_edit.actions.add": "add", + "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", -- 2.47.3