diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index a72512e..91457ef 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -1,11 +1,11 @@ /** * @author fenris */ -type int = number; +declare type int = number; /** * @author fenris */ -type float = number; +declare 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 */ -type type_pseudopointer = { +declare 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,51 +2693,6 @@ 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 @@ -3854,6 +3809,55 @@ 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 { /** */ @@ -4039,55 +4043,6 @@ 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 fa6a73c..6ff86ef 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 (g && (g = 0, op[0] && (_ = 0)), _) try { + while (_) 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,136 +8710,6 @@ 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' @@ -9579,12 +9449,6 @@ var lib_plankton; * @author fenris */ class class_relation { - /** - * @author fenris - */ - check(value, reference) { - return this.predicate(value, reference); - } /** * @author fenris */ @@ -9594,6 +9458,12 @@ var lib_plankton; this.name = name; this.predicate = predicate; } + /** + * @author fenris + */ + check(value, reference) { + return this.predicate(value, reference); + } /** * @author fenris */ @@ -10070,7 +9940,7 @@ var lib_plankton; h = 0; } else if (q === r) { - h = ((0 / 3) + lib_plankton.math.mod((g - b) / (c * 6), 1)); + h = ((0 / 3) + ((g - b) / (c * 6))); } else if (q === g) { h = ((1 / 3) + ((b - r) / (c * 6))); @@ -11868,6 +11738,190 @@ 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' @@ -12387,190 +12441,6 @@ 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/misc/conf-example.json b/misc/conf-example.json index cf5b37e..7f8190c 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": true + "use_central_europe_specific_datetime_inputs": false } } diff --git a/source/base/functions.ts b/source/base/functions.ts index a4721c9..274127d 100644 --- a/source/base/functions.ts +++ b/source/base/functions.ts @@ -1,38 +1,7 @@ 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( @@ -89,6 +58,6 @@ namespace _dali { return view_mode_decode(mode_descriptor); } - } + } } diff --git a/source/base/model.ts b/source/base/model.ts deleted file mode 100644 index 26847c6..0000000 --- a/source/base/model.ts +++ /dev/null @@ -1,8 +0,0 @@ -namespace _dali.model -{ - - /** - */ - let events : Array<_dali.type.event_entry> = []; - -} diff --git a/source/base/types.ts b/source/base/types.ts index ac35b84..da79c50 100644 --- a/source/base/types.ts +++ b/source/base/types.ts @@ -31,22 +31,6 @@ 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_key = string; - - /** */ export type event_object = { @@ -77,11 +61,7 @@ namespace _dali.type /** */ - export type event_entry = { - id : (null | local_resource_event_id); - key : event_key; - object : event_object; - }; + export type local_resource_event_id = int; /** diff --git a/source/base/widget.ts b/source/base/widget.ts new file mode 100644 index 0000000..f971ca8 --- /dev/null +++ b/source/base/widget.ts @@ -0,0 +1,18 @@ +namespace _dali +{ + + /** + * @todo outsource + */ + export abstract class class_widget + { + + /** + */ + public abstract load( + target_element : Element + ) : Promise; + + } + +} diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 81f9572..1ddbdb1 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -18,7 +18,6 @@ "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", @@ -50,13 +49,6 @@ "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", "widget.weekview.controls.apply": "Laden", - "widget.calendar_edit.actions.add": "Kalender anlegen", - "widget.calendar_edit.actions.change": "ändern", - "widget.calendar_edit.actions.remove": "löschen", - "widget.event_edit.actions.add": "anlegen", - "widget.event_edit.actions.change": "ändern", - "widget.event_edit.actions.remove": "löschen", - "widget.sources.create": "anlegen", "page.login.title": "Anmelden", "page.login.internal.name": "Name", "page.login.internal.password": "Kennwort", @@ -78,9 +70,14 @@ "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 63bee86..25ad7bf 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -18,7 +18,6 @@ "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", @@ -50,13 +49,6 @@ "widget.weekview.controls.week": "Week", "widget.weekview.controls.count": "Count", "widget.weekview.controls.apply": "Load", - "widget.calendar_edit.actions.add": "add calendar", - "widget.calendar_edit.actions.change": "change", - "widget.calendar_edit.actions.remove": "delete", - "widget.event_edit.actions.add": "add", - "widget.event_edit.actions.change": "change", - "widget.event_edit.actions.remove": "delete", - "widget.sources.create": "create", "page.login.title": "Login", "page.login.internal.name": "name", "page.login.internal.password": "password", @@ -77,10 +69,15 @@ "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 d8151a6..e8eb5f4 100644 --- a/source/index.html.tpl +++ b/source/index.html.tpl @@ -31,10 +31,6 @@ document.addEventListener( -
-
-
-
diff --git a/source/main.ts b/source/main.ts index df3090d..1713e10 100644 --- a/source/main.ts +++ b/source/main.ts @@ -82,11 +82,23 @@ 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"), @@ -97,7 +109,6 @@ namespace _dali } ); await update(); - await _dali.overlay.initialize(); lib_plankton.call.loop( () => { update(); diff --git a/source/overlay.ts b/source/overlay.ts deleted file mode 100644 index 6195c85..0000000 --- a/source/overlay.ts +++ /dev/null @@ -1,75 +0,0 @@ -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_add/logic.ts b/source/pages/calendar_add/logic.ts new file mode 100644 index 0000000..7438bb4 --- /dev/null +++ b/source/pages/calendar_add/logic.ts @@ -0,0 +1,228 @@ +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 new file mode 100644 index 0000000..3b573e7 --- /dev/null +++ b/source/pages/calendar_add/templates/default.html.tpl @@ -0,0 +1,5 @@ +
+

{{label}}

+
+
+
diff --git a/source/pages/calendar_edit/logic.ts b/source/pages/calendar_edit/logic.ts new file mode 100644 index 0000000..0ed083d --- /dev/null +++ b/source/pages/calendar_edit/logic.ts @@ -0,0 +1,187 @@ +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 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); + return Promise.resolve(undefined); + } + ); + +} diff --git a/source/pages/calendar_edit/templates/default.html.tpl b/source/pages/calendar_edit/templates/default.html.tpl new file mode 100644 index 0000000..62d2f1a --- /dev/null +++ b/source/pages/calendar_edit/templates/default.html.tpl @@ -0,0 +1,5 @@ +
+

{{label}}

+
+
+
diff --git a/source/pages/event_add/logic.ts b/source/pages/event_add/logic.ts new file mode 100644 index 0000000..f5b5d90 --- /dev/null +++ b/source/pages/event_add/logic.ts @@ -0,0 +1,235 @@ +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 new file mode 100644 index 0000000..3cfad06 --- /dev/null +++ b/source/pages/event_add/templates/default.html.tpl @@ -0,0 +1,5 @@ +
+

{{label}}

+
+
+
diff --git a/source/pages/event_edit/logic.ts b/source/pages/event_edit/logic.ts new file mode 100644 index 0000000..4e4bab6 --- /dev/null +++ b/source/pages/event_edit/logic.ts @@ -0,0 +1,195 @@ +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 new file mode 100644 index 0000000..2d47742 --- /dev/null +++ b/source/pages/event_edit/templates/default.html.tpl @@ -0,0 +1,5 @@ +
+

{{label}}

+
+
+
diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index d2f2b15..7caeb15 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 : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher( + const widget_mode_switcher : _dali.class_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher( [ { "mode": _dali.type.enum_view_mode.week, @@ -57,16 +57,8 @@ 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 = async () => { - await widget_weekview.update_entries(); - await widget_sources.update(); - }; // hint { if (! await _dali.backend.is_logged_in()) @@ -80,56 +72,19 @@ namespace _dali.pages.overview } // sources { - widget_sources = new _dali.widgets.sources.class_widget_sources( - _dali.backend.calendar_list, + 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, { - "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) { case _dali.type.enum_access_level.none: @@ -140,60 +95,31 @@ namespace _dali.pages.overview case _dali.type.enum_access_level.edit: case _dali.type.enum_access_level.view: { - read_only = true; + lib_plankton.zoo_page.set( + { + "name": "calendar_edit", + "parameters": { + "read_only": "yes", + "calendar_id": entry.id, + } + } + ); break; } case _dali.type.enum_access_level.admin: { - read_only = false; + lib_plankton.zoo_page.set( + { + "name": "calendar_edit", + "parameters": { + "read_only": "no", + "calendar_id": entry.id, + } + } + ); 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); @@ -213,16 +139,6 @@ 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) { case _dali.type.enum_access_level.none: @@ -232,90 +148,34 @@ namespace _dali.pages.overview } case _dali.type.enum_access_level.view: { - read_only = true; + lib_plankton.zoo_page.set( + { + "name": "event_edit", + "parameters": { + "read_only": "yes", + "calendar_id": calendar_id, + "event_id": event_id, + } + } + ); break; } case _dali.type.enum_access_level.edit: case _dali.type.enum_access_level.admin: { - read_only = false; + lib_plankton.zoo_page.set( + { + "name": "event_edit", + "parameters": { + "read_only": "no", + "calendar_id": calendar_id, + "event_id": event_id, + } + } + ); 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 { @@ -350,85 +210,17 @@ 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( - { + lib_plankton.zoo_page.set( + { + "name": "event_add", + "parameters": { "calendar_id": null, - "event_name": "", - "event_begin": lib_plankton.call.convey( - date, - [ - x => ({ - "timezone_shift": 0, - "date": date, - "time": {"hour": 12, "minute": 0, "second": 0} - }), - lib_plankton.pit.from_datetime, - x => lib_plankton.pit.shift_hour(x, 0), - lib_plankton.pit.to_datetime, - ] - ), - "event_end": lib_plankton.call.convey( - date, - [ - x => ({ - "timezone_shift": 0, - "date": date, - "time": {"hour": 12, "minute": 0, "second": 0} - }), - lib_plankton.pit.from_datetime, - x => lib_plankton.pit.shift_hour(x, +1), - lib_plankton.pit.to_datetime, - ] - ), - "event_location": null, - "event_link": null, - "event_description": null, - }, - { - "read_only": false, - "action_cancel": () => { - _dali.overlay.toggle({"mode": false}); - }, - "action_add": (data) => { - _dali.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 - } - ); - }, + "year": date.year, + "month": date.month, + "day": date.day, } - ); - _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 c0f6377..1164246 100644 --- a/source/resources/backend.ts +++ b/source/resources/backend.ts @@ -14,16 +14,6 @@ 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") @@ -38,7 +28,6 @@ namespace _dali.backend /** - * meant for translation of the API values */ function access_level_decode( access_level_encoded : ("none" | "view" | "edit" | "admin") @@ -63,14 +52,6 @@ namespace _dali.backend "corner": "zeitbild", } ); - _cache = lib_plankton.cache.make( - /* - lib_plankton.storage.memory.implementation_chest( - { - } - ) - */ - ); return Promise.resolve(undefined); } @@ -181,27 +162,19 @@ namespace _dali.backend /** - * @todo mneh … */ export async function is_logged_in( ) : Promise { - 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 ((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; } @@ -574,7 +547,6 @@ namespace _dali.backend /** - * @todo Möglichkeit den Kalender zu ändern */ export async function calendar_event_change( calendar_id : _dali.type.calendar_id, @@ -623,20 +595,12 @@ namespace _dali.backend export async function events( from_pit : lib_plankton.pit.type_pit, to_pit : lib_plankton.pit.type_pit, - { - "calendar_ids": calendar_ids = null, - } - : - { + options : { 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; @@ -647,6 +611,13 @@ namespace _dali.backend > > { + options = Object.assign( + { + "calendar_ids": null, + }, + options + ); + return ( call( lib_plankton.http.enum_method.get, @@ -657,11 +628,11 @@ namespace _dali.backend "to": to_pit, }, ( - (calendar_ids === null) + (options.calendar_ids === null) ? {} : - {"calendar_ids": calendar_ids.join(",")} + {"calendar_ids": options.calendar_ids.join(",")} ) ) ) @@ -670,7 +641,6 @@ 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/style/main.css b/source/style/main.css index 2f85e01..e1d417e 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -20,39 +20,6 @@ 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; @@ -89,14 +56,12 @@ nav a:hover a { text-decoration: none; - color: hsl(var(--hue), 0%, 87.5%); + color: hsl(var(--hue), 50%, 50%); } a:hover { - color: hsl(var(--hue), 0%, 100%); - border-bottom: 2px solid hsl(0, 0%, 100%); - transition: 1s ease color; + color: hsl(var(--hue), 50%, 75%); } input,select,textarea diff --git a/source/style/widget-sources.css b/source/style/widget-sources.css index efc6e46..bfcb618 100644 --- a/source/style/widget-sources.css +++ b/source/style/widget-sources.css @@ -1,13 +1,9 @@ .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/calendar_edit/logic.ts b/source/widgets/calendar_edit/logic.ts deleted file mode 100644 index f4327eb..0000000 --- a/source/widgets/calendar_edit/logic.ts +++ /dev/null @@ -1,241 +0,0 @@ -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_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 : (null | type_value); - - - /** - */ - public constructor( - { - "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, - } - : - { - 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); - } - = - { - } - ) - { - 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 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(); - } - }, - ] - : - [] - ) - // 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))) - ? - [ - { - "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 deleted file mode 100644 index 7d1b942..0000000 --- a/source/widgets/event_edit/logic.ts +++ /dev/null @@ -1,282 +0,0 @@ -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/listview/logic.ts b/source/widgets/listview/logic.ts index c79f673..9523e4c 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 implements lib_plankton.zoo_widget.interface_widget + export class class_widget_listview extends _dali.class_widget { /** @@ -94,6 +94,7 @@ 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 fd7c9b0..50a8e53 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 implements lib_plankton.zoo_widget.interface_widget + export class class_widget_mode_switcher extends _dali.class_widget { /** @@ -47,6 +47,7 @@ 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 53a4931..e9b57da 100644 --- a/source/widgets/sources/logic.ts +++ b/source/widgets/sources/logic.ts @@ -13,234 +13,58 @@ namespace _dali.widgets.sources /** */ - export class class_widget_sources implements lib_plankton.zoo_widget.interface_widget + export class class_widget_sources extends _dali.class_widget { /** - * [dependency] */ - private get_entries : (() => Promise>); + private keys : Array; + + + /** + */ + private data : Record; /** - * [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( - get_entries : (() => Promise>), - { - "action_open": action_open = ((calendar_id) => {}), - "action_toggle_visibility": action_toggle_visibility = ((calendar_id) => {}), - "action_create": action_create = (() => {}), - } - : - { + entries : Array, + options : { action_open ?: ((entry : type_entry) => void); action_toggle_visibility ?: ((entry : type_entry) => void); - action_create ?: (() => void); - } - = - { - } + } = {} ) { - // 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, - }) - ) - ), - } - ) + options = Object.assign( + { + "action_open": (calendar_id) => {}, + "action_toggle_visibility": (calendar_id) => {}, + }, + options ); - // 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); - } - ); - } - ); - } + super(); + this.keys = []; + this.data = {}; + entries.forEach( + (entry) => { + const key : string = entry.id.toFixed(0); + this.keys.push(key); + this.data[key] = entry; + } + ); + this.action_open = options.action_open; + this.action_toggle_visibility = options.action_toggle_visibility; } @@ -249,11 +73,100 @@ namespace _dali.widgets.sources */ public async load( target_element : Element - ) - : Promise + ) : Promise { - this.container = target_element; - await this.update(); + 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); } } diff --git a/source/widgets/sources/templates/main.html.tpl b/source/widgets/sources/templates/main.html.tpl index ba432fd..3f9a9a7 100644 --- a/source/widgets/sources/templates/main.html.tpl +++ b/source/widgets/sources/templates/main.html.tpl @@ -1,6 +1,3 @@ -
-
    - {{entries}} -
- {{label_create}} -
+
    + {{entries}} +
diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index 457d9e9..85686df 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -4,7 +4,6 @@ namespace _dali.widgets.weekview /** */ type type_entry = { - key : _dali.type.event_key; calendar_id : _dali.type.calendar_id; calendar_name : string; hue : float; @@ -29,17 +28,20 @@ namespace _dali.widgets.weekview /** */ - export class class_widget_weekview implements lib_plankton.zoo_widget.interface_widget + export class class_widget_weekview extends _dali.class_widget { /** - * [dependency] */ private get_entries : type_get_entries; /** - * [hook] + */ + private container : (null | Element); + + + /** */ private action_select_event : ( ( @@ -53,7 +55,6 @@ namespace _dali.widgets.weekview /** - * [hook] */ private action_select_day : ( ( @@ -64,55 +65,11 @@ 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, - { - "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, - } - : - { + options : { action_select_event ?: ( ( calendar_id : _dali.type.calendar_id, @@ -129,70 +86,21 @@ namespace _dali.widgets.weekview => void ); - initial_year ?: (null | int); - initial_week ?: (null | int); - initial_count ?: int; - } - = - {} + } = {} ) { - // dependencies - this.get_entries = get_entries; - - // 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_key, - { - element : HTMLElement; - hash : string; - } - >( - event_key => event_key - ) - ); - 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( + options = Object.assign( { - "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, + "action_select_day": (date) => {}, + "action_select_event": (calendar_id, access_level, event_id) => {}, }, - [ - x => lib_plankton.json.encode(x), - ] + options ); + super(); + this.get_entries = get_entries; + this.container = null; + this.action_select_day = options.action_select_day; + this.action_select_event = options.action_select_event; } @@ -292,480 +200,644 @@ namespace _dali.widgets.weekview /** + * @todo kein "while" */ - private get_entries_wrapped( + 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< { - "calendar_ids": calendar_ids = null, - "timezone_shift": timezone_shift = 0, - } - : - { - calendar_ids ?: (null | Array<_dali.type.calendar_id>); - timezone_shift ?: int; - } - = - { - } - ) - : Promise> - { - return this.get_entries( - lib_plankton.pit.from_ywd( + sources : lib_plankton.map.type_map< + _dali.type.calendar_id, { - "year": this.year, - "week": this.week, - "day": 1, - }, - { - "timezone_shift": timezone_shift, + name : string; + access_level : _dali.type.enum_access_level; + hue : float; } - ), - lib_plankton.pit.from_ywd( - { - "year": this.year, - "week": (this.week + this.count), - "day": 1, - }, - { - "timezone_shift": timezone_shift, - } - ), - calendar_ids - ); - } - - - /** - */ - private async entry_insert( - entry : type_entry - ) : Promise<(null | HTMLElement)> - { - const selector : string = lib_plankton.string.coin( - ".weekview-cell[rel=\"{{rel}}\"] > .weekview-events", - { - "rel": lib_plankton.pit.date_format(entry.event_object.begin.date), - } - ); - 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}}", - { - "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), - } - ), - "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 entry_add( - entry : type_entry - ) : Promise - { - const dom_entry : (null | HTMLElement) = await this.entry_insert(entry); - if (dom_entry === null) - { - // do nothing - } - else - { - this.event_map.set( - entry.key, - { - "element": dom_entry, - "hash": class_widget_weekview.entry_hash(entry), - } - ); - } - } - - - /** - */ - private async entry_update( - key : _dali.type.event_key, - entry : type_entry - ) : Promise - { - 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) - { - // 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< + >; + 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; } >; } - > = ( - 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 - ), - }; + > + } + > + { + 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, + 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 + } } ) ); - 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(""), - } + // 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 + { + const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); + options = Object.assign( + { + "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; + } + > = 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", + { + "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(""), + } + ) ) - ).join(""); - } - // listeners + ) + ).join(""); + } + + + /** + */ + private async update( + year : int, + week : int, + count : int, + options : { + update_controls ?: boolean; + } = {} + ) : Promise + { + options = Object.assign( + { + "update_controls": true, + }, + options + ); + const context : Element = this.container; + // controls { - 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); - } + 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); + } + } + // table + { + context.querySelector(".weekview-table tbody").innerHTML = await this.table_rows( + { + "calendar_ids": null, + // TODO + "from": { + "year": year, + "week": week + }, + // TODO + "to": { + "year": year, + "week": (week + count) + }, + "timezone_shift": /*conf.timezone_shift*/0, + } + ); + // 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); } /** */ public toggle_visibility( - calendar_id : _dali.type.calendar_id, - { - "mode": mode = null, - } - : - { - mode ?: (null | boolean); - } - = - { - } + calendar_id : _dali.type.calendar_id ) : void { this.container.querySelectorAll(".weekview-event_entry").forEach( @@ -773,13 +845,11 @@ 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 - { - element.classList.toggle("weekview-cell-hidden", mode ?? undefined); + else { + element.classList.toggle("weekview-cell-hidden"); } } ); @@ -813,43 +883,39 @@ namespace _dali.widgets.weekview this.container = target_element.querySelector(".weekview"); // controls { - [ - { - "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(); + target_element.querySelector(".weekview-control-apply").addEventListener( + "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, } ); } ); } - await this.update_controls(); - await this.update_table(); - await this.update_entries(); - + // 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, + } + ); + } return Promise.resolve(undefined); } diff --git a/source/widgets/weekview/templates/main.html.tpl b/source/widgets/weekview/templates/main.html.tpl index 30a6ee5..0ebb5f0 100644 --- a/source/widgets/weekview/templates/main.html.tpl +++ b/source/widgets/weekview/templates/main.html.tpl @@ -12,6 +12,7 @@ {{label_control_count}} +
diff --git a/tools/makefile b/tools/makefile index 2ca4fa3..3195a2b 100644 --- a/tools/makefile +++ b/tools/makefile @@ -36,9 +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 @@ -70,20 +72,6 @@ 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/*) @@ -91,6 +79,34 @@ 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-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/*) @@ -118,22 +134,23 @@ 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}/base/model.ts \ ${dir_source}/resources/conf.ts \ ${dir_source}/resources/backend.ts \ ${dir_source}/widgets/sources/logic.ts \ ${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 …" diff --git a/tools/update-plankton b/tools/update-plankton index b652c8d..7577b00 100755 --- a/tools/update-plankton +++ b/tools/update-plankton @@ -14,7 +14,6 @@ modules="${modules} json" modules="${modules} string" modules="${modules} random" modules="${modules} map" -modules="${modules} cache" modules="${modules} color" # modules="${modules} xml" modules="${modules} map" @@ -24,7 +23,6 @@ modules="${modules} url" modules="${modules} pit" modules="${modules} www_form" modules="${modules} translate" -modules="${modules} zoo-widget" modules="${modules} zoo-page" modules="${modules} zoo-form" modules="${modules} zoo-input"