From b2eeb3f1fe3237f156ec1c4bfa2aec3c18ed8cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Thu, 3 Apr 2025 11:47:47 +0000 Subject: [PATCH 1/3] [task-193] [int] --- misc/conf-example.json | 2 +- source/logic/backend.ts | 57 ++++++++ source/pages/invite_handle/logic.ts | 155 ++++++++++++++++++++++ source/pages/invite_handle/structure.html | 19 +++ source/pages/invite_handle/style.css | 15 +++ tools/makefile | 7 +- 6 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 source/pages/invite_handle/logic.ts create mode 100644 source/pages/invite_handle/structure.html create mode 100644 source/pages/invite_handle/style.css diff --git a/misc/conf-example.json b/misc/conf-example.json index 5eb6264..9a3665c 100644 --- a/misc/conf-example.json +++ b/misc/conf-example.json @@ -2,7 +2,7 @@ "backend": { "scheme": "http", "host": "localhost", - "port": 7979, + "port": 4916, "path_base": "" } } diff --git a/source/logic/backend.ts b/source/logic/backend.ts index ec1eb96..01446a9 100644 --- a/source/logic/backend.ts +++ b/source/logic/backend.ts @@ -485,4 +485,61 @@ namespace _espe.backend ); } + + /** + */ + export async function invite_examine( + key : string + ) : Promise< + { + membership_number_mode : int; + membership_number_value : (null | string); + name_mode : int; + name_value : string; + email_address_mode : int; + email_address_value : (null | string); + groups_mode : int; + groups_value : Array; + } + > + { + return abstract_call( + "GET", + lib_plankton.string.coin( + "/invite/examine?key={{key}}", + { + "key": key + } + ) + ); + } + + + /** + */ + export async function invite_accept( + key : string, + data : { + membership_number_value : string; + name_value : string; + email_address_value : (null | string); + groups_value : Array; + } + ) : Promise + { + return abstract_call( + "POST", + "/invite/accept", + { + "data": { + "key": key, + "membership_number_value": data.membership_number_value, + "name_value": data.name_value, + "email_address_value": data.email_address_value, + "groups_value": data.groups_value, + } + } + ); + } + } diff --git a/source/pages/invite_handle/logic.ts b/source/pages/invite_handle/logic.ts new file mode 100644 index 0000000..2e7062e --- /dev/null +++ b/source/pages/invite_handle/logic.ts @@ -0,0 +1,155 @@ +/* +Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend +Copyright (C) 2024 Christian Fraß + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later +version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see +. + */ + +lib_plankton.zoo_page.register( + "invite_handle", + async (parameters, target_element) => { + // parameters + const key : string = parameters["key"]; + + target_element.appendChild(template_request("invite_handle")); + + /** + * @todo invite_handle-title + */ + + const data : { + membership_number_mode : int; + membership_number_value : (null | string); + name_mode : int; + name_value : string; + email_address_mode : int; + email_address_value : (null | string); + groups_mode : int; + groups_value : Array; + } = await _espe.backend.invite_examine(key); + + const form = new lib_plankton.zoo_form.class_form< + { + membership_number_value : (null | string); + name_value : string; + email_address_value : (null | string); + groups_value : Array; + }, + { + membership_number_value : string; + name_value : string; + email_address_value : string; + groups_value : Array; + } + >( + value => ({ + "membership_number_value": (value.membership_number_value ?? ""), + "name_value": value.name_value, + "email_address_value": (value.email_address_value ?? ""), + "groups_value": value.groups_value, + }), + representation => ({ + "membership_number_value": representation.membership_number_value, + "name_value": representation.name_value, + "email_address_value": representation.email_address_value, + "groups_value": representation.groups_value, + }), + new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "name_value", + "input": new lib_plankton.zoo_input.class_input_text( + { + "read_only": (data.name_mode <= 1), + } + ), + /** + * @todo translate + */ + "label": "Name", + }, + { + "name": "membership_number_value", + "input": new lib_plankton.zoo_input.class_input_text( + { + "read_only": (data.membership_number_mode <= 1), + } + ), + /** + * @todo translate + */ + "label": "Mitgliedsnummer", + }, + { + "name": "email_address_value", + "input": new lib_plankton.zoo_input.class_input_text( + { + "read_only": (data.email_address_mode <= 1), + } + ), + /** + * @todo translate + */ + "label": "E-Mail-Adresse", + }, + { + "name": "groups_value", + "input": new lib_plankton.zoo_input.class_input_list( + () => new lib_plankton.zoo_input.class_input_text(), + { + /** + * @todo does not work yet + */ + // "read_only": (data.groups_mode <= 1), + } + ), + /** + * @todo translate + */ + "label": "Gruppen", + }, + ] + ), + [ + { + "label": "Senden", + "procedure": async (get_value, get_representation) => { + const value = await get_value(); + await _espe.backend.invite_accept( + key, + { + "membership_number_value": value.membership_number_value, + "name_value": value.name_value, + "email_address_value": value.email_address_value, + "groups_value": value.groups_value, + } + ); + /** + * @todo redirect + */ + /* + lib_plankton.zoo_page.set({"name": "view", "parameters": {"id": id}}); + */ + }, + } + ] + ); + await form.setup(target_element.querySelector(".invite_handle-form") as HTMLElement); + await form.input_write( + { + "membership_number_value": data.membership_number_value, + "name_value": data.name_value, + "email_address_value": data.email_address_value, + "groups_value": data.groups_value, + } + ); + } +); diff --git a/source/pages/invite_handle/structure.html b/source/pages/invite_handle/structure.html new file mode 100644 index 0000000..7abba5e --- /dev/null +++ b/source/pages/invite_handle/structure.html @@ -0,0 +1,19 @@ + + + diff --git a/source/pages/invite_handle/style.css b/source/pages/invite_handle/style.css new file mode 100644 index 0000000..791713b --- /dev/null +++ b/source/pages/invite_handle/style.css @@ -0,0 +1,15 @@ +/* +Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend +Copyright (C) 2024 Christian Fraß + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later +version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see +. + */ + diff --git a/tools/makefile b/tools/makefile index 24dfef8..9968b9b 100644 --- a/tools/makefile +++ b/tools/makefile @@ -47,6 +47,7 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/pages/register/logic.ts \ ${dir_source}/pages/password_change_init/logic.ts \ ${dir_source}/pages/password_change_exec/logic.ts \ + ${dir_source}/pages/invite_handle/logic.ts \ ${dir_source}/logic/main.ts @ ${cmd_log} "logic | compile …" @ ${cmd_mkdir} $(dir $@) @@ -68,7 +69,8 @@ ${dir_build}/style.css: \ ${dir_source}/pages/view/style.css \ ${dir_source}/pages/register/style.css \ ${dir_source}/pages/password_change_init/style.css \ - ${dir_source}/pages/password_change_exec/style.css + ${dir_source}/pages/password_change_exec/style.css \ + ${dir_source}/pages/invite_handle/style.css @ ${cmd_log} "style …" @ ${cmd_mkdir} $(dir $@) @ ${cmd_cat} $^ > $@ @@ -83,7 +85,8 @@ ${dir_build}/index.html: \ ${dir_source}/pages/view/structure.html \ ${dir_source}/pages/register/structure.html \ ${dir_source}/pages/password_change_init/structure.html \ - ${dir_source}/pages/password_change_exec/structure.html + ${dir_source}/pages/password_change_exec/structure.html \ + ${dir_source}/pages/invite_handle/structure.html @ ${cmd_log} "structure …" @ ${cmd_mkdir} $(dir $@) @ tools/make-index $^ > $@ -- 2.39.5 From 76a2d7dff4ebbc4d942ae9398fedbf2fe7f3721e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sat, 12 Apr 2025 10:19:59 +0000 Subject: [PATCH 2/3] [task-193] [int] --- lib/plankton/plankton.d.ts | 1034 +++-- lib/plankton/plankton.js | 3380 +++++++++++++---- source/data/localization/deu.loc.json | 4 +- source/data/localization/eng.loc.json | 4 +- source/logic/backend.ts | 35 +- source/logic/main.ts | 5 + source/pages/invite_handle/logic.ts | 73 +- source/pages/invite_list/logic.ts | 81 + .../style.css => invite_list/structure.html} | 11 +- source/pages/list/logic.ts | 2 +- source/pages/view/style.css | 15 - source/style/style.css | 19 +- tools/makefile | 5 +- 13 files changed, 3577 insertions(+), 1091 deletions(-) create mode 100644 source/pages/invite_list/logic.ts rename source/pages/{invite_handle/style.css => invite_list/structure.html} (80%) diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 883b649..1598f00 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -6,29 +6,6 @@ type int = number; * @author fenris */ type float = number; -/** - * @author fenris - */ -type type_date = { - year: int; - month: int; - day: int; -}; -/** - * @author fenris - */ -type type_time = { - hour: int; - minute: int; - second: int; -}; -/** - * @author fenris - */ -type type_datetimeobject = { - date: type_date; - time: type_time; -}; declare class Buffer { constructor(x: string, modifier?: string); toString(modifier?: string): string; @@ -247,6 +224,12 @@ declare namespace lib_plankton.base { /** */ function object_merge(core: Record, mantle: Record): Record; + /** + */ + function buffer_show(buffer: Buffer, { "block_size": option_block_size, "break_char": option_break_char, }?: { + block_size?: int; + break_char?: string; + }): string; } declare module lib_plankton.pod { /** @@ -297,7 +280,10 @@ declare module lib_plankton.pod { */ class class_pod { private subject; - private constructor(); + constructor(subject: type_pod); + tear(): type_pod; + static empty(): class_pod; + static filled(value: type_value): class_pod; is_empty(): boolean; is_filled(): boolean; cull(): type_value; @@ -372,36 +358,6 @@ declare namespace lib_plankton.call { */ function promise_delay(promise: type_promise, delay: int): type_promise; } -declare namespace lib_plankton.call { - /** - */ - class CancellablePromise extends Promise { - /** - */ - private cancelled; - /** - */ - private interval; - /** - */ - private subject; - /** - */ - constructor(executor: ((resolve: any, reject: any) => void)); - /** - */ - private clear; - /** - */ - then(onfulfilled?: ((value: type_result) => (type_next_resolved | PromiseLike)), onrejected?: ((reason: any) => (type_next_rejected | PromiseLike))): Promise; - /** - */ - catch(x: any): Promise; - /** - */ - cancel(): void; - } -} /** * initializer might be obsolete, since promises are reusable after having been resolved or rejected */ @@ -565,25 +521,25 @@ declare namespace lib_plankton.call { * @param {Object} args * @author fenris */ - function args2list(args: any): Array; + export function args2list(args: any): Array; /** * just the empty function; useful for some callbacks etc. * * @author fenris */ - function nothing(): void; + export function nothing(): void; /** * just the identity; useful for some callbacks etc.; defined as function instead of const for using type parameters * * @author fenris */ - function id(x: type_value): type_value; + export function id(x: type_value): type_value; /** * just the identity; useful for some callbacks etc. * * @author fenris */ - function const_(x: type_value): ((y: any) => type_value); + export function const_(x: type_value): ((y: any) => type_value); /** * composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions) * @@ -591,7 +547,7 @@ declare namespace lib_plankton.call { * @param {function} function_g * @author fenris */ - function compose(function_f: ((type_x: any) => type_y), function_g: ((type_y: any) => type_z)): ((value: type_x) => type_z); + export function compose(function_f: ((type_x: any) => type_y), function_g: ((type_y: any) => type_z)): ((value: type_x) => type_z); /** * transforms a function with sequential input to a function with leveled input; example: add(2,3) = curryfy(add)(2)(3) * @@ -599,27 +555,46 @@ declare namespace lib_plankton.call { * @return {function} the currified version of the in put function * @author fenris */ - function curryfy(f: Function): Function; + export function curryfy(f: Function): Function; /** * @author fenris */ - function convey(value: any, functions: Array): any; + export function convey(value: any, functions: Array): any; + /** + */ + class class_value_wrapper { + /** + */ + private value; + /** + */ + constructor(value: type_value); + /** + */ + convey(function_: ((value: type_value) => type_value_result)): class_value_wrapper; + /** + */ + cull(): type_value; + } + /** + */ + export function wrap(value: type_value): class_value_wrapper; /** * @author fenris */ - function timeout(procedure: (() => void), delay_in_seconds: float): int; + export function timeout(procedure: (() => void), delay_in_seconds: float): int; /** * Promise version of "setTimeout" * * @author fenris */ - function defer(seconds: float, action: (() => type_result)): Promise; + export function defer(seconds: float, action: (() => type_result)): Promise; /** * a definition for a value being "defined" * * @author neuc */ - function is_def(obj: type_value, options?: { + export function is_def(obj: type_value, options?: { null_is_valid?: boolean; }): boolean; /** @@ -627,7 +602,7 @@ declare namespace lib_plankton.call { * * @author neuc */ - function def_val(value: any, default_value: any, options?: { + export function def_val(value: any, default_value: any, options?: { type?: (null | string); null_is_valid?: boolean; }): any; @@ -638,7 +613,7 @@ declare namespace lib_plankton.call { * @return {function} * @author fenris */ - function attribute(name: string): ((object: type_object) => type_attribute); + export function attribute(name: string): ((object: type_object) => type_attribute); /** * provides a method of a class as a regular function; useful for processing lists of objects * @@ -646,48 +621,33 @@ declare namespace lib_plankton.call { * @return {function} * @author fenris */ - function method(name: string): ((object: type_object) => type_output); + export function method(name: string): ((object: type_object) => type_output); /** * @author fenris */ - type type_coproduct = { + export type type_coproduct = { kind: string; data?: any; }; /** * @author fenris */ - function distinguish(coproduct: type_coproduct, handlers: Record type_output)>, options?: { + export function distinguish(coproduct: type_coproduct, handlers: Record type_output)>, options?: { fallback?: (null | ((coproduct?: type_coproduct) => type_output)); }): type_output; /** - * for rate_limit_check - * - * @author fenris */ - type type_mana_snapshot = { - timestamp: float; - value: float; + export function try_catch_wrap(get_value: (() => type_value)): { + value: (null | type_value); + error: (null | any); }; /** - * rate limiting algorithm, based on the idea of mana (magic power) in video games: - * - an actor has a fixed mana capacity, i.e. the maximum amount of available power - * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) - * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it - * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time - * - * @author fenris */ - function rate_limit_check(setup: { - capacity: float; - regeneration_rate: float; - get_snapshot: (() => Promise<(null | type_mana_snapshot)>); - set_snapshot: ((snapshot: type_mana_snapshot) => Promise); - update_snapshot: ((timestamp: float, value_increment: float) => Promise); - }, heft: float): Promise<{ - granted: boolean; - seconds: (null | float); + export function try_catch_wrap_async(get_value: (() => Promise)): Promise<{ + value: (null | type_value); + error: (null | any); }>; + export {}; } declare namespace lib_plankton.file { /** @@ -900,13 +860,26 @@ declare namespace lib_plankton.code { } declare namespace lib_plankton.json { /** - * @author fenris */ - function encode(x: any, formatted?: boolean): string; + type type_source = any; + /** + */ + type type_target = string; /** * @author fenris */ - function decode(x: string): any; + export function encode(source: type_source, options?: { + formatted?: boolean; + }): type_target; + /** + * @author fenris + */ + export function decode(target: type_target): type_source; + /** + * @author fenris + */ + export function implementation_code(): lib_plankton.code.type_code; + export {}; } declare namespace lib_plankton.json { /** @@ -960,6 +933,16 @@ declare namespace lib_plankton.base64 { decode(x: string): string; } } +declare namespace lib_plankton.email { + /** + */ + function send(smtp_credentials: { + host: string; + port: int; + username: string; + password: string; + }, sender: string, receivers: Array, subject: string, content: string): Promise; +} declare namespace lib_plankton.log { /** */ @@ -970,124 +953,265 @@ declare namespace lib_plankton.log { warning = 3, error = 4 } - /** - */ - function level_order(level1: enum_level, level2: enum_level): boolean; - /** - */ - function level_show(level: enum_level): string; /** */ type type_entry = { level: enum_level; incident: string; - details: Record; + tags: Array; + details: any; }; + /** + */ + type type_channel_description = lib_plankton.call.type_coproduct; + /** + */ + type type_channel_logic = { + send: ((entry: type_entry) => void); + }; + /** + */ + type type_logger_data = Array; + /** + */ + type type_logger_logic = Array; + /** + */ + type type_format_definition = ({ + kind: "jsonl"; + data: { + structured: boolean; + }; + } | { + kind: "human_readable"; + data: {}; + }); +} +declare namespace lib_plankton.log { + /** + */ + function level_order(level1: enum_level, level2: enum_level): boolean; + /** + */ + function level_show(level: enum_level, { "abbreviated": option_abbreviated, }?: { + abbreviated?: boolean; + }): string; + /** + */ + function level_decode(level_string: string): enum_level; +} +declare namespace lib_plankton.log { + /** + * @todo use label + */ + function get_logger_logic(logger_data: type_logger_data): type_logger_logic; + /** + */ + function format_entry(format_definition: type_format_definition, entry: type_entry): string; + /** + */ + function parse_format_definition(format_definition_raw: any): type_format_definition; +} +declare namespace lib_plankton.log.channel.filtered { + /** + */ + type type_predicate = ((entry: type_entry) => boolean); + /** + */ + type type_subject = { + /** + * @todo check if it has to be logic + */ + core: type_channel_logic; + predicate: type_predicate; + }; + /** + */ + function predicate_incident(substring: string): type_predicate; + /** + */ + function predicate_level(threshold: enum_level): type_predicate; + /** + */ + function predicate_tag(tag: string): type_predicate; + /** + * combines other predicates in disjunctive normal form + */ + function predicate_complex(definition: Array>): type_predicate; + /** + */ + function send(subject: type_subject, entry: type_entry): void; + /** + */ + function logic(subject: type_subject): type_channel_logic; +} +declare namespace lib_plankton.log.channel.minlevel { + /** + */ + type type_subject = { + /** + * @todo check if it has to be logic + */ + core: type_channel_logic; + threshold: enum_level; + }; + /** + */ + function send(subject: type_subject, entry: type_entry): void; + /** + */ + function logic(subject: type_subject): type_channel_logic; } /** - * @deprecated - * @todo remove + * output for writing log entries to web console */ -declare namespace lib_plankton.log { - function level_push(level: int): void; - function level_pop(): void; - function indent_push(indent: int): void; - function indent_pop(): void; - function indent_inc(): void; - function indent_dec(): void; +declare namespace lib_plankton.log.channel.console_ { /** - * @author fenris */ - function write({ "message": message, "type": type, "prefix": prefix, "level": level, "indent": indent, }: { - message?: string; - type?: string; - prefix?: string; - level?: int; - indent?: int; + type type_subject = {}; + /** + * @todo tags + */ + function send(subject: type_subject, entry: type_entry): void; + /** + */ + function logic(subject: type_subject): type_channel_logic; +} +declare namespace lib_plankton.log { + /** + */ + function get_channel_logic(channel_description: type_channel_description): type_channel_logic; +} +declare namespace lib_plankton.log { + /** + */ + function default_logger(): type_logger_data; +} +declare namespace lib_plankton.log { + /** + */ + function set_main_logger(logger_data: type_logger_data): void; + /** + * consumes a log entry, i.e. sends it to all channels + */ + function send_(logger: type_logger_logic, entry: type_entry): void; + /** + * [convenience] + * + * @todo rename to "send" + */ + function debug_(logger: type_logger_logic, incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; }): void; -} -declare namespace lib_plankton.log { /** + * [convenience] + * + * @todo rename to "info" */ - abstract class class_channel { - /** - */ - abstract add(entry: type_entry): void; - } -} -declare namespace lib_plankton.log { + function info_(logger: type_logger_logic, incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** - * output for writing log entries to web console + * [convenience] + * + * @todo rename to "notice" */ - class class_channel_console extends class_channel { - /** - */ - add(entry: type_entry): void; - } -} -declare namespace lib_plankton.log { + function notice_(logger: type_logger_logic, incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** - * decorator for filtering out log entries below a certain level threshold + * [convenience] + * + * @todo rename to "warning" */ - class class_channel_minlevel extends class_channel { - /** - */ - private core; - /** - */ - private threshold; - /** - */ - constructor(core: class_channel, threshold: enum_level); - /** - */ - add(entry: type_entry): void; - } -} -declare namespace lib_plankton.log { + function warning_(logger: type_logger_logic, incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** + * [convenience] + * + * @todo rename to "error" */ - function channel_make(description: { - kind: string; - data?: { - [key: string]: any; - }; - }): class_channel; + function error_(logger: type_logger_logic, incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** + * [convenience] */ - type type_configuration = Array; + function _send(entry: type_entry): void; /** + * [convenience] */ - function conf_default(): type_configuration; -} -declare namespace lib_plankton.log { + function _debug(incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** - * pushes a new configuration on the stack and activates it + * [convenience] */ - function conf_push(channels: type_configuration): void; + function _info(incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** - * pops the current active configuration from the stack + * [convenience] */ - function conf_pop(): void; + function _notice(incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** - * consumes a log entry, i.e. sends it to the currently active outputs + * [convenience] */ - function add(entry: type_entry): void; + function _warning(incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** + * [convenience] */ - function debug(incident: string, details?: Record): void; + function _error(incident: string, { "tags": option_tags, "details": option_details, }?: { + tags?: Array; + details?: any; + }): void; /** + * [convenience] + * + * @deprecated use ._debug instead! */ - function info(incident: string, details?: Record): void; + function debug(incident: string, details?: any, tags?: Array): void; /** + * [convenience] + * + * @deprecated use ._info instead! */ - function notice(incident: string, details?: Record): void; + function info(incident: string, details?: any, tags?: Array): void; /** + * [convenience] + * + * @deprecated use ._notice instead! */ - function warning(incident: string, details?: Record): void; + function notice(incident: string, details?: any, tags?: Array): void; /** + * [convenience] + * + * @deprecated use ._warning instead! */ - function error(incident: string, details?: Record): void; + function warning(incident: string, details?: any, tags?: Array): void; + /** + * [convenience] + * + * @deprecated use ._error instead! + */ + function error(incident: string, details?: any, tags?: Array): void; } declare var plain_text_to_html: (text: string) => string; /** @@ -1125,7 +1249,7 @@ declare namespace lib_plankton.string { * @return {Array} * @author fenris */ - function split(chain: string, separator?: string): Array; + function split(chain: string, separator: string): Array; /** * @author neu3no */ @@ -1211,6 +1335,9 @@ declare namespace lib_plankton.string { /** */ function slice(str: string, size: int): Array; + /** + */ + function capitalize(str: string): string; } /** * @deprecated @@ -1254,114 +1381,105 @@ declare var make_logger: (prefix: any, current_loglevel: any) => (obj: any, lvl: declare namespace lib_plankton.object { /** * @author fenris + * @deprecated use the "??" operator instead */ - function fetch(object: Object, fieldname: string, fallback?: type_value, escalation?: int): type_value; + function fetch(object: Object, fieldname: string, options?: { + fallback?: type_value; + escalate?: boolean; + }): type_value; /** - * @author fenris */ - function map(object_from: { - [key: string]: type_from; - }, transformator: (value_from: type_from, key?: string) => type_to): { - [key: string]: type_to; - }; + function map(object_from: Record, transformator: ((value_from: type_from, key?: string) => type_to)): Record; /** - * @desc gibt ein Objekt mit bestimmten Einträgen des Eingabe-Objekts zurück - * @author fenris + * gibt ein Objekt mit bestimmten Einträgen des Eingabe-Objekts zurück */ - function filter(object_from: { - [key: string]: type_value; - }, predicate: (value_from: type_value, key?: string) => boolean): { - [key: string]: type_value; - }; + function filter(object_from: Record, predicate: ((value_from: type_value, key?: string) => boolean)): Record; /** - * @desc wandelt ein Array mit Einträgen der Form {key,value} in ein entsprechendes Objekt um - * @author fenris + * wandelt ein Array mit Einträgen der Form {key,value} in ein entsprechendes Objekt um + * + * @deprecated use Object.fromEntries instead! */ function from_array(array: Array<{ key: string; value: type_value; - }>): { - [key: string]: type_value; - }; + }>): Record; /** - * @desc wandelt ein Objekt in ein entsprechendes Array mit Einträgen der Form {key,value} um - * @author fenris + * wandelt ein Objekt in ein entsprechendes Array mit Einträgen der Form {key,value} um + * + * @deprecated use Object.entries insetad! */ - function to_array(object: { - [key: string]: type_value; - }): Array<{ + function to_array(object: Record): Array<{ key: string; value: type_value; }>; /** - * @desc gibt eine Liste von Schlüsseln eines Objekts zurück - * @author fenris + * gibt eine Liste von Schlüsseln eines Objekts zurück + * + * @deprecated use Object.keys instead! */ - function keys(object: { - [key: string]: any; - }): Array; + function keys(object: Record): Array; /** - * @desc gibt eine Liste von Werten eines Objekts zurück - * @author fenris + * gibt eine Liste von Werten eines Objekts zurück + * + * @deprecated use Object.values instead! */ - function values(object: { - [key: string]: type_value; - }): Array; + function values(object: Record): Array; /** - * @desc liest ein Baum-artiges Objekt an einer bestimmten Stelle aus - * @author fenris + * liest ein Baum-artiges Objekt an einer bestimmten Stelle aus */ - function path_read(object: Object, path: string, fallback?: type_value, escalation?: int): type_value; + function path_read(object: Object, path: string, options?: { + fallback?: type_value; + escalate?: boolean; + }): type_value; /** - * @desc schreibt einen Wert an eine bestimmte Stelle in einem Baum-artigen Objekt - * @author fenris + * schreibt einen Wert an eine bestimmte Stelle in einem Baum-artigen Objekt */ function path_write(object: Object, path: string, value: type_value, construct?: boolean): void; /** - * @desc prüft ob ein Objekt einem bestimmten Muster entspricht - * @param {Object} object das zu prüfende Objekt - * @param {Object} pattern das einzuhaltende Muster - * @param {Function} connlate eine Funktion zum Feststellen der Gleichheit von Einzelwerten - * @author fenris + * prüft ob ein Objekt einem bestimmten Muster entspricht + * + * @deprecated not very useful */ - function matches(object: Object, pattern: Object, collate?: typeof instance_collate): boolean; + function matches(object: Record, pattern: Record, options?: { + collate?: ((value_pattern: type_value_pattern, value_object: type_value_object) => boolean); + }): boolean; /** - * @desc erzeugt eine Projektion eines Baum-artigen Objekts in ein Listen-artiges Objekt - * @param {string} [separator] welches Zeichen als Trenner zwischen zwei Pfad-Schritten verwendet werden soll - * @author fenris + * erzeugt eine Projektion eines Baum-artigen Objekts in ein Listen-artiges Objekt */ - function flatten(value: any, separator?: string, key_for_element?: (index: int) => string): Object; + function flatten(value: any, options?: { + separator?: string; + key_for_array_element?: ((index: int) => string); + }): Record; /** - * @author fenris + * @deprecated use Object.assign instead! */ - function clash(x: { - [key: string]: any; - }, y: { - [key: string]: any; - }, { "overwrite": overwrite, "hooks": { "existing": hook_existing, }, }?: { + function clash(x: Record, y: Record, options?: { overwrite?: boolean; hooks?: { - existing?: (key?: string, value_old?: any, value_new?: any) => void; + existing?: ((key?: string, value_old?: any, value_new?: any) => void); }; - }): { - [key: string]: any; - }; + }): Record; + /** + * @deprecated use Object.assign instead! + */ + function patch(core: (null | Record), mantle: (null | Record), options?: { + deep?: boolean; + path?: (null | string); + }): void; + /** + * @deprecated use Object.assign instead! + */ + function patched(core: Record, mantle: Record, options?: { + deep?: boolean; + }): Record; + /** + * @deprecated use Object.assign instead! + */ + function attached(object: Record, key: string, value: any): Record; /** * @author fenris */ - function patch(core: Object, mantle: Object, deep?: boolean, path?: string): void; - /** - * @author fenris - */ - function patched(core: Object, mantle: Object, deep?: boolean): Object; - /** - * @author fenris - */ - function attached(object: Object, key: string, value: any): Object; - /** - * @author fenris - */ - function copy(object: Object): Object; + function copy(object: Record): Record; } declare namespace lib_plankton.translate { /** @@ -1490,6 +1608,7 @@ declare namespace lib_plankton.database { type type_description_insert = { table_name: string; values: Record; + returning?: (null | string); }; /** */ @@ -1534,6 +1653,7 @@ declare namespace lib_plankton.database { * @author fenris */ type type_database = { + wrap_name: ((name: string) => string); query_free_get: ((query: type_query) => Promise); query_free_put: ((query: type_query) => Promise); query_free_set: ((query: type_query) => Promise); @@ -1706,7 +1826,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; @@ -1774,6 +1894,301 @@ declare namespace lib_plankton.storage.localstorage { }[]>; } } +declare namespace lib_plankton.map { + /** + */ + type type_pair = { + key: type_key; + value: type_value; + }; + /** + * @author fenris + */ + type type_map = { + size: (() => int); + has: ((key: type_key) => boolean); + get: ((key: type_key, fallback?: lib_plankton.pod.type_pod) => type_value); + set: ((key: type_key, value: type_value) => void); + delete: ((key: type_key) => void); + iterate: ((procedure: ((value: type_value, key?: type_key) => void)) => void); + }; +} +declare namespace lib_plankton.map { + /** + */ + function clear(map: type_map): void; + /** + */ + function keys(map: type_map): Array; + /** + */ + function values(map: type_map): Array; + /** + */ + function dump(map: type_map): Array>; + /** + */ + function show(map: type_map, options?: { + show_key?: ((key: type_key) => string); + show_value?: ((value: type_value) => string); + }): string; +} +declare namespace lib_plankton.map.simplemap { + /** + */ + type type_subject = { + data: Record; + }; + /** + */ + function make(options?: { + data?: Record; + }): type_subject; + /** + */ + function size(subject: type_subject): int; + /** + */ + function has(subject: type_subject, key: string): boolean; + /** + */ + function get_safe(subject: type_subject, key: string): lib_plankton.pod.type_pod; + /** + */ + function get(subject: type_subject, key: string, fallback?: lib_plankton.pod.type_pod): type_value; + /** + */ + function set(subject: type_subject, key: string, value: type_value): void; + /** + */ + function delete_(subject: type_subject, key: string): void; + /** + */ + function iterate(subject: type_subject, procedure: ((value?: type_value, key?: string) => void)): void; + /** + */ + function implementation_map(subject: type_subject): type_map; +} +declare namespace lib_plankton.map.hashmap { + /** + * we base the hashmap on a simplemap, whos keys are the hashes and whos values are the key/value-pairs + */ + type type_subject = { + hashing: ((key: type_key) => string); + core: lib_plankton.map.simplemap.type_subject>; + }; + /** + */ + function make(hashing: ((key: type_key) => string), options?: { + pairs?: Array>; + }): type_subject; + /** + */ + function size(subject: type_subject): int; + /** + */ + function has(subject: type_subject, key: type_key): boolean; + /** + */ + function get(subject: type_subject, key: type_key, fallback?: lib_plankton.pod.type_pod): type_value; + /** + */ + function set(subject: type_subject, key: type_key, value: type_value): void; + /** + */ + function delete_(subject: type_subject, key: type_key): void; + /** + */ + function iterate(subject: type_subject, procedure: ((value?: type_value, key?: type_key) => void)): void; + /** + */ + function implementation_map(subject: type_subject): type_map; +} +declare namespace lib_plankton.map.collatemap { + /** + */ + type type_collation = ((key1: type_key, key2: type_key) => boolean); + /** + */ + export type type_subject = { + collation: type_collation; + pairs: Array>; + }; + /** + */ + export function make(collation: type_collation, options?: { + pairs?: Array>; + }): type_subject; + /** + */ + export function size(subject: type_subject): int; + /** + */ + export function has(subject: type_subject, key: type_key): boolean; + /** + * @todo use .find + */ + export function get(subject: type_subject, key: type_key, fallback?: lib_plankton.pod.type_pod): type_value; + /** + */ + export function set(subject: type_subject, key: type_key, value: type_value): void; + /** + */ + export function delete_(subject: type_subject, key: type_key): void; + /** + */ + export function iterate(subject: type_subject, function_: ((value?: type_value, key?: type_key) => void)): void; + /** + */ + export function implementation_map(subject: type_subject): type_map; + export {}; +} +declare namespace lib_plankton.pit { + /** + */ + type type_date = { + year: int; + month: int; + day: int; + }; + /** + */ + type type_ywd = { + year: int; + week: int; + day: int; + }; + /** + */ + type type_time = { + hour: int; + minute: int; + second: int; + }; + /** + */ + type type_datetime = { + timezone_shift: int; + date: type_date; + time: (null | type_time); + }; + /** + */ + type type_pit = int; +} +declare namespace lib_plankton.pit { + /** + * @todo complete + */ + function timezone_name_to_timezone_shift(timezone_name: string): int; + /** + */ + function date_object_get_week_of_year(date: Date): int; + /** + */ + function to_unix_timestamp(pit: type_pit): int; + /** + */ + function from_unix_timestamp(unix_timestamp: int): type_pit; + /** + */ + function to_date_object(pit: type_pit): Date; + /** + * @todo test + */ + function to_datetime(pit: type_pit, { "timezone_shift": option_timezone_shift, }?: { + timezone_shift?: int; + }): type_datetime; + /** + */ + function from_datetime(datetime: type_datetime): type_pit; + /** + */ + function is_before(pit: type_pit, reference: type_pit): boolean; + /** + */ + function is_between(pit: type_pit, reference_left: type_pit, reference_right: type_pit): boolean; + /** + */ + function shift_day(pit: type_pit, increment: int): type_pit; + /** + */ + function shift_week(pit: type_pit, increment: int): type_pit; + /** + */ + function trunc_week(pit: type_pit): type_pit; + /** + */ + function now(): type_pit; + /** + * @param year year according to specified timezone shift + * @param week week according to specified timezone shift + * @return the begin of the week (monday, 00:00) + */ + function from_ywd(ywd: type_ywd, { "timezone_shift": option_timezone_shift, }?: { + timezone_shift?: int; + }): type_pit; + /** + * @todo timezone + */ + function to_ywd(pit: type_pit, { "timezone_shift": option_timezone_shift, }?: { + timezone_shift?: int; + }): type_ywd; + /** + * computes the point in time for switching to central european summer time + * + * @todo write tests + */ + function cest_switch_on(year: int): type_pit; + /** + * computes the point in time for switching away from central european summer time + * + * @todo write tests + */ + function cest_switch_off(year: int): type_pit; + /** + */ + function timezone_shift_ce(pit: type_pit): int; + /** + * [convenience] + */ + function to_datetime_ce(pit: type_pit): type_datetime; + /** + */ + function datetime_translate(datetime: type_datetime, timezone_shift: int): type_datetime; + /** + * [convenience] + */ + function datetime_translate_ce(datetime: type_datetime): type_datetime; + /** + */ + function timezone_shift_format(timezone_shift: int): string; + /** + */ + function date_format(date: type_date): string; + /** + */ + function time_format(time: type_time, { "show_seconds": option_show_seconds, }?: { + show_seconds?: boolean; + }): string; + /** + * @todo show timezone + */ + function datetime_format(datetime: (null | type_datetime), { "timezone_indicator": option_timezone_indicator, "show_timezone": option_show_timezone, "adjust_to_ce": option_adjust_to_ce, "omit_date": option_omit_date, }?: { + timezone_indicator?: string; + show_timezone?: boolean; + adjust_to_ce?: boolean; + omit_date?: boolean; + }): string; + /** + */ + function timespan_format(from: type_datetime, to: (null | type_datetime), { "timezone_indicator": option_timezone_indicator, "show_timezone": option_show_timezone, "adjust_to_ce": option_adjust_to_ce, "omit_date": option_omit_date, }?: { + timezone_indicator?: string; + show_timezone?: boolean; + adjust_to_ce?: boolean; + omit_date?: boolean; + }): string; +} declare namespace lib_plankton.zoo_input { /** * @author fenris @@ -1821,6 +2236,40 @@ declare namespace lib_plankton.zoo_input { write(value: type_value_outer): Promise; } } +declare namespace lib_plankton.zoo_input { + /** + * @author fenris + */ + class class_input_soft implements interface_input<(null | type_value_core)> { + /** + */ + private core; + /** + */ + private dom_set; + /** + */ + private dom_wrapper; + /** + */ + constructor(core: interface_input, options?: {}); + /** + */ + private toggle; + /** + * [implementation] + */ + setup(parent: HTMLElement): Promise; + /** + * [implementation] + */ + read(): Promise<(null | type_value_core)>; + /** + * [implementation] + */ + write(value: (null | type_value_core)): Promise; + } +} declare namespace lib_plankton.zoo_input { /** * @author fenris @@ -1942,7 +2391,7 @@ declare namespace lib_plankton.zoo_input { /** * @author fenris */ - class class_input_date implements interface_input<(null | type_date)> { + class class_input_date implements interface_input<(null | lib_plankton.pit.type_date)> { /** */ private required; @@ -1961,11 +2410,11 @@ declare namespace lib_plankton.zoo_input { /** * [implementation] */ - read(): Promise<(null | type_date)>; + read(): Promise<(null | lib_plankton.pit.type_date)>; /** * [implementation] */ - write(value: (null | type_date)): Promise; + write(value: (null | lib_plankton.pit.type_date)): Promise; } } declare namespace lib_plankton.zoo_input { @@ -2111,6 +2560,9 @@ declare namespace lib_plankton.zoo_input { * @author fenris */ export class class_input_list implements interface_input> { + /** + */ + private read_only; /** */ private element_input_factory; @@ -2126,6 +2578,7 @@ declare namespace lib_plankton.zoo_input { /** */ constructor(element_input_factory: (() => interface_input), options?: { + read_only?: boolean; translations?: type_translations; }); /** @@ -2206,7 +2659,7 @@ declare namespace lib_plankton.zoo_input { /** * @author fenris */ - class class_input_time implements interface_input<(null | type_time)> { + class class_input_time implements interface_input<(null | lib_plankton.pit.type_time)> { /** */ private dom_input; @@ -2220,11 +2673,11 @@ declare namespace lib_plankton.zoo_input { /** * [implementation] */ - read(): Promise<(null | type_time)>; + read(): Promise<(null | lib_plankton.pit.type_time)>; /** * [implementation] */ - write(value: (null | type_time)): Promise; + write(value: (null | lib_plankton.pit.type_time)): Promise; } } declare namespace lib_plankton.zoo_input { @@ -2257,6 +2710,83 @@ declare namespace lib_plankton.zoo_input { write(value: type_record): Promise; } } +declare namespace lib_plankton.zoo_input { + /** + */ + class class_input_hashmap implements lib_plankton.zoo_input.interface_input> { + /** + */ + private hash_key; + /** + */ + private core; + /** + */ + constructor(hash_key: ((key: type_key) => string), key_input_factory: (() => lib_plankton.zoo_input.interface_input), value_input_factory: (() => lib_plankton.zoo_input.interface_input)); + /** + * [implementation] + */ + setup(parent: HTMLElement): Promise; + /** + * [implementation] + */ + read(): Promise>; + /** + * [implementation] + */ + write(map: lib_plankton.map.type_map): Promise; + } +} +declare namespace lib_plankton.zoo_input { + /** + */ + class class_input_datetime implements interface_input { + /** + */ + private core; + /** + */ + constructor(options?: { + label_timezone_shift?: string; + label_date?: string; + label_time?: string; + }); + /** + */ + setup(parent: HTMLElement): Promise; + /** + */ + read(): Promise; + /** + */ + write(value: lib_plankton.pit.type_datetime): Promise; + } +} +declare namespace lib_plankton.zoo_input { + /** + * for central europe with daylight saving time feature + */ + class class_input_datetime_central_europe implements interface_input { + /** + */ + private core; + /** + */ + constructor(options?: { + label_date?: string; + label_time?: string; + }); + /** + */ + setup(parent: HTMLElement): Promise; + /** + */ + read(): Promise; + /** + */ + write(value: lib_plankton.pit.type_datetime): Promise; + } +} declare namespace lib_plankton.zoo_form { /** */ diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 3a89377..0217965 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -1,22 +1,7 @@ -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); /* This file is part of »bacterio-plankton:base«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -36,7 +21,7 @@ along with »bacterio-plankton:base«. If not, see »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -77,7 +62,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:base«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -123,7 +108,7 @@ along with »bacterio-plankton:base«. If not, see »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -267,7 +252,7 @@ function instance_show(value) { /* This file is part of »bacterio-plankton:base«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -286,11 +271,11 @@ along with »bacterio-plankton:base«. If not, see this.actions[id](information)); } - }; + } /** * @author frac */ - class_observer.prototype.rollout = function () { - var _this = this; - this.buffer.forEach(function (information) { return _this.notify(information, false); }); + rollout() { + this.buffer.forEach(information => this.notify(information, false)); this.buffer = []; - }; - return class_observer; -}()); + } +} /** * @author frac */ @@ -378,7 +358,7 @@ export interface interface_writeable { /* This file is part of »bacterio-plankton:base«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base« is free software: you can redistribute it and/or modify @@ -397,27 +377,42 @@ along with »bacterio-plankton:base«. If not, see x.toString()).join(",") + "]")); + } +} +/* +This file is part of »bacterio-plankton:base«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:base« 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:base« 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:base«. If not, see . + */ var lib_plankton; (function (lib_plankton) { var base; @@ -427,9 +422,8 @@ var lib_plankton; * * @author fenris */ - function get_current_timestamp(rounded) { - if (rounded === void 0) { rounded = false; } - var x = (Date.now() / 1000); + function get_current_timestamp(rounded = false) { + const x = (Date.now() / 1000); return (rounded ? Math.round(x) : x); ; } @@ -440,12 +434,30 @@ var lib_plankton; return Object.assign(core, mantle); } base.object_merge = object_merge; + /** + */ + function buffer_show(buffer, { "block_size": option_block_size = 20, "break_char": option_break_char = "\n", } = {}) { + let output = ""; + let count = 0; + // @ts-ignore + for (const entry of buffer) { + count = ((count + 1) % option_block_size); + output += ((typeof (entry) === "string") + ? + entry.charCodeAt(0) + : + entry).toString(16).toUpperCase().padStart(2, "0"); + output += ((count === 0) ? option_break_char : " "); + } + return output; + } + base.buffer_show = buffer_show; })(base = lib_plankton.base || (lib_plankton.base = {})); })(lib_plankton || (lib_plankton = {})); /* This file is part of »bacterio-plankton:pod«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:pod« is free software: you can redistribute it and/or modify @@ -549,7 +561,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:pod«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:pod« is free software: you can redistribute it and/or modify @@ -573,6 +585,9 @@ var lib_plankton; */ class class_pod { constructor(subject) { this.subject = subject; } + tear() { return this.subject; } + static empty() { return (new class_pod(pod.make_empty())); } + static filled(value) { return (new class_pod(pod.make_filled(value))); } is_empty() { return (!pod.is_filled(this.subject)); } is_filled() { return pod.is_filled(this.subject); } cull() { return pod.cull(this.subject); } @@ -587,7 +602,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:call«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:call« is free software: you can redistribute it and/or modify @@ -749,90 +764,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:call«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:call« 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:call« 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:call«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var call; - (function (call) { - /** - */ - class CancellablePromise extends Promise { - /** - */ - constructor(executor) { - super((resolve, reject) => { }); - this.subject = (new Promise((resolve, reject) => { - Promise.race([ - new Promise(executor), - new Promise((resolve_, reject_) => { - this.interval = setInterval(() => { - if (!this.cancelled) { - // do nothing - } - else { - reject_(new Error("cancelled")); - this.clear(); - } - }, 0); - }), - ]) - .then(resolve, reject); - })); - this.cancelled = false; - this.interval = null; - } - /** - */ - clear() { - if (this.interval === null) { - // do nothing - } - else { - clearInterval(this.interval); - this.interval = null; - } - } - /** - */ - then(onfulfilled, onrejected) { - this.clear(); - return this.subject.then(onfulfilled, onrejected); - } - /** - */ - catch(x) { - this.clear(); - return this.subject.catch(x); - } - /** - */ - cancel() { - this.cancelled = true; - this.clear(); - } - } - call.CancellablePromise = CancellablePromise; - })(call = lib_plankton.call || (lib_plankton.call = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:call«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:call« is free software: you can redistribute it and/or modify @@ -999,7 +931,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:call«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:call« is free software: you can redistribute it and/or modify @@ -1170,7 +1102,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:call«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:call« is free software: you can redistribute it and/or modify @@ -1261,7 +1193,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:call«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:call« is free software: you can redistribute it and/or modify @@ -1374,6 +1306,31 @@ var lib_plankton; return result; } call.convey = convey; + /** + */ + class class_value_wrapper { + /** + */ + constructor(value) { + this.value = value; + } + /** + */ + convey(function_) { + return (new class_value_wrapper(function_(this.value))); + } + /** + */ + cull() { + return this.value; + } + } + /** + */ + function wrap(value) { + return (new class_value_wrapper(value)); + } + call.wrap = wrap; /** * @author fenris */ @@ -1480,69 +1437,42 @@ var lib_plankton; } call.distinguish = distinguish; /** - * rate limiting algorithm, based on the idea of mana (magic power) in video games: - * - an actor has a fixed mana capacity, i.e. the maximum amount of available power - * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth) - * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it - * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time - * - * @author fenris */ - async function rate_limit_check(setup, heft) { - if (heft > setup.capacity) { - return Promise.resolve({ - "granted": false, - "seconds": null, - }); + function try_catch_wrap(get_value) { + try { + return { + "value": get_value(), + "error": null, + }; } - else { - // get current value - const current_timestamp = (Date.now() / 1000); - const old_snapshot_raw = (await setup.get_snapshot()); - const old_snapshot = (old_snapshot_raw - ?? - { "timestamp": current_timestamp, "value": setup.capacity }); - const seconds_passed = (current_timestamp - old_snapshot.timestamp); - const current_value = Math.min(setup.capacity, (old_snapshot.value - + - (setup.regeneration_rate - * - seconds_passed))); - // analyze - if (current_value < heft) { - // too less - const seconds_needed = ((setup.regeneration_rate <= 0) - ? null - : ((heft - old_snapshot.value) / setup.regeneration_rate)); - return Promise.resolve({ - "granted": false, - "seconds": ((seconds_needed === null) ? null : (seconds_needed - seconds_passed)), - }); - } - else { - // enough -> update snapshot - const new_value = (current_value - heft); - // set_snapshot - if (old_snapshot_raw === null) { - await setup.set_snapshot({ "timestamp": current_timestamp, "value": new_value }); - } - else { - await setup.update_snapshot(current_timestamp, (new_value - old_snapshot.value)); - } - return Promise.resolve({ - "granted": true, - "seconds": 0, - }); - } + catch (error) { + return { + "value": null, + "error": error, + }; } } - call.rate_limit_check = rate_limit_check; + call.try_catch_wrap = try_catch_wrap; + /** + */ + function try_catch_wrap_async(get_value) { + return (get_value() + .then((value) => Promise.resolve({ + "value": value, + "error": null, + })) + .catch((reason) => Promise.resolve({ + "value": null, + "error": reason, + }))); + } + call.try_catch_wrap_async = try_catch_wrap_async; })(call = lib_plankton.call || (lib_plankton.call = {})); })(lib_plankton || (lib_plankton = {})); /* This file is part of »bacterio-plankton:file«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:file« is free software: you can redistribute it and/or modify @@ -1647,7 +1577,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1666,7 +1596,7 @@ along with »bacterio-plankton:code«. If not, see »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1685,7 +1615,7 @@ along with »bacterio-plankton:code«. If not, see »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1724,7 +1654,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1778,7 +1708,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1821,7 +1751,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1876,7 +1806,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1926,7 +1856,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -1978,7 +1908,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -2038,7 +1968,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:code«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:code« is free software: you can redistribute it and/or modify @@ -2089,7 +2019,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:json«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:json« is free software: you can redistribute it and/or modify @@ -2112,23 +2042,36 @@ var lib_plankton; /** * @author fenris */ - function encode(x, formatted = false) { - return JSON.stringify(x, undefined, formatted ? "\t" : undefined); + function encode(source, options = {}) { + options = Object.assign({ + "formatted": false, + }, options); + return JSON.stringify(source, undefined, (options.formatted ? "\t" : undefined)); } json.encode = encode; /** * @author fenris */ - function decode(x) { - return JSON.parse(x); + function decode(target) { + return JSON.parse(target); } json.decode = decode; + /** + * @author fenris + */ + function implementation_code() { + return { + "encode": x => encode(x), + "decode": decode, + }; + } + json.implementation_code = implementation_code; })(json = lib_plankton.json || (lib_plankton.json = {})); })(lib_plankton || (lib_plankton = {})); /* This file is part of »bacterio-plankton:json«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:json« is free software: you can redistribute it and/or modify @@ -2178,7 +2121,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:base64«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base64« is free software: you can redistribute it and/or modify @@ -2217,7 +2160,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:base64«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:base64« is free software: you can redistribute it and/or modify @@ -2264,25 +2207,81 @@ var lib_plankton; base64.class_base64 = class_base64; })(base64 = lib_plankton.base64 || (lib_plankton.base64 = {})); })(lib_plankton || (lib_plankton = {})); -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + 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 { + 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]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +/* +This file is part of »bacterio-plankton:email«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:email« 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:lang« 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:email«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var email; + (function (email) { + /** + */ + function send(smtp_credentials, sender, receivers, subject, content) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, Promise.reject(new Error("not implemented"))]; + }); + }); + } + email.send = send; + })(email = lib_plankton.email || (lib_plankton.email = {})); +})(lib_plankton || (lib_plankton = {})); /* This file is part of »bacterio-plankton:log«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:log« is free software: you can redistribute it and/or modify @@ -2313,6 +2312,31 @@ var lib_plankton; enum_level[enum_level["error"] = 4] = "error"; })(enum_level = log.enum_level || (log.enum_level = {})); ; + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { /** */ function level_order(level1, level2) { @@ -2321,282 +2345,33 @@ var lib_plankton; log.level_order = level_order; /** */ - function level_show(level) { - switch (level) { - case enum_level.debug: return "debug"; - case enum_level.info: return "info"; - case enum_level.notice: return "notice"; - case enum_level.warning: return "warning"; - case enum_level.error: return "error"; - default: return "(unknown)"; + function level_show(level, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["abbreviated"], option_abbreviated = _c === void 0 ? false : _c; + if (option_abbreviated) { + switch (level) { + case log.enum_level.debug: return "DBG"; + case log.enum_level.info: return "INF"; + case log.enum_level.notice: return "NTC"; + case log.enum_level.warning: return "WRN"; + case log.enum_level.error: return "ERR"; + default: return "(unknown)"; + } + } + else { + switch (level) { + case log.enum_level.debug: return "debug"; + case log.enum_level.info: return "info"; + case log.enum_level.notice: return "notice"; + case log.enum_level.warning: return "warning"; + case log.enum_level.error: return "error"; + default: return "(unknown)"; + } } } log.level_show = level_show; - })(log = lib_plankton.log || (lib_plankton.log = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:log«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:log« 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:lang« 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:lang«. If not, see . - */ -/** - * @deprecated - * @todo remove - */ -var lib_plankton; -(function (lib_plankton) { - var log; - (function (log) { - /** - * @author fenris - */ - /*export*/ var level_stack = [0]; - function level_push(level) { level_stack.push(level); } - log.level_push = level_push; - function level_pop() { if (level_stack.length > 1) { - level_stack.pop(); - } } - log.level_pop = level_pop; - function level_get() { return level_stack.slice(-1)[0]; } - /* - export function level_inc() : void {level_push(level_get()+1);} - export function level_dec() : void {level_push(level_get()-1);} - */ - /** - * @author fenris - */ - var indent_stack = [0]; - function indent_push(indent) { indent_stack.push(indent); } - log.indent_push = indent_push; - function indent_pop() { if (indent_stack.length > 1) { - indent_stack.pop(); - } } - log.indent_pop = indent_pop; - function indent_get() { return level_stack.slice(-1)[0]; } - function indent_inc() { level_push(level_get() + 1); } - log.indent_inc = indent_inc; - function indent_dec() { level_push(level_get() - 1); } - log.indent_dec = indent_dec; - /** - * @author fenris - */ - function write(_a) { - var message = _a["message"], _b = _a["type"], type = _b === void 0 ? null : _b, _c = _a["prefix"], prefix = _c === void 0 ? null : _c, _d = _a["level"], level = _d === void 0 ? 0 : _d, _e = _a["indent"], indent = _e === void 0 ? 0 : _e; - var entry = { - "level": ((type === null) - ? lib_plankton.log.enum_level.info - : { - "debug": lib_plankton.log.enum_level.debug, - "info": lib_plankton.log.enum_level.info, - "notice": lib_plankton.log.enum_level.notice, - "warning": lib_plankton.log.enum_level.warning, - "error": lib_plankton.log.enum_level.error - }[type]), - "incident": message, - "details": { - "prefix": prefix, - "level": level, - "indent": indent - } - }; - lib_plankton.log.add(entry); - } - log.write = write; - })(log = lib_plankton.log || (lib_plankton.log = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:log«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:log« 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:lang« 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:log«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var log; - (function (log) { /** */ - var class_channel = /** @class */ (function () { - function class_channel() { - } - return class_channel; - }()); - log.class_channel = class_channel; - })(log = lib_plankton.log || (lib_plankton.log = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:log«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:log« 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:lang« 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:log«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var log; - (function (log) { - /** - * output for writing log entries to web console - */ - var class_channel_console = /** @class */ (function (_super) { - __extends(class_channel_console, _super); - function class_channel_console() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - */ - class_channel_console.prototype.add = function (entry) { - var _a; - var renderers = (_a = {}, - _a[log.enum_level.debug] = { - "renderer": function (i, d) { return console.log(i, d); }, - "show_level": true - }, - _a[log.enum_level.info] = { - "renderer": function (i, d) { return console.info(i, d); }, - "show_level": false - }, - _a[log.enum_level.notice] = { - "renderer": function (i, d) { return console.log(i, d); }, - "show_level": true - }, - _a[log.enum_level.warning] = { - "renderer": function (i, d) { return console.warn(i, d); }, - "show_level": false - }, - _a[log.enum_level.error] = { - "renderer": function (i, d) { return console.error(i, d); }, - "show_level": false - }, - _a); - var setting = renderers[entry.level]; - setting.renderer(((setting.show_level - ? ("[" + log.level_show(entry.level) + "]" + " ") - : "") - + - ("" + entry.incident + "")), entry.details); - }; - return class_channel_console; - }(log.class_channel)); - log.class_channel_console = class_channel_console; - })(log = lib_plankton.log || (lib_plankton.log = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:log«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:log« 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:lang« 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:log«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var log; - (function (log) { - /** - * decorator for filtering out log entries below a certain level threshold - */ - var class_channel_minlevel = /** @class */ (function (_super) { - __extends(class_channel_minlevel, _super); - /** - */ - function class_channel_minlevel(core, threshold) { - var _this = _super.call(this) || this; - _this.core = core; - _this.threshold = threshold; - return _this; - } - /** - */ - class_channel_minlevel.prototype.add = function (entry) { - if (!log.level_order(this.threshold, entry.level)) { - // do nothing - } - else { - this.core.add(entry); - } - }; - return class_channel_minlevel; - }(log.class_channel)); - log.class_channel_minlevel = class_channel_minlevel; - })(log = lib_plankton.log || (lib_plankton.log = {})); -})(lib_plankton || (lib_plankton = {})); -/* -This file is part of »bacterio-plankton:log«. - -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' - - -»bacterio-plankton:log« 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:lang« 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:log«. If not, see . - */ -var lib_plankton; -(function (lib_plankton) { - var log; - (function (log) { - /** - */ - function translate_level(level_string) { + function level_decode(level_string) { return { "debug": log.enum_level.debug, "info": log.enum_level.info, @@ -2605,36 +2380,318 @@ var lib_plankton; "error": log.enum_level.error }[level_string]; } - /** - */ - function channel_make(description) { - var _a; - switch (description.kind) { - default: { - throw (new Error("unhandled log channel kind: " + description.kind)); - break; - } - case "console": { - return (new log.class_channel_minlevel(new log.class_channel_console(), translate_level((_a = description.data["threshold"]) !== null && _a !== void 0 ? _a : "debug"))); - break; - } - } - } - log.channel_make = channel_make; - /** - */ - function conf_default() { - return [ - new log.class_channel_minlevel(new log.class_channel_console(), log.enum_level.notice), - ]; - } - log.conf_default = conf_default; + log.level_decode = level_decode; })(log = lib_plankton.log || (lib_plankton.log = {})); })(lib_plankton || (lib_plankton = {})); /* This file is part of »bacterio-plankton:log«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + /** + * @todo use label + */ + function get_logger_logic(logger_data) { + return logger_data.map(function (channel_description) { return lib_plankton.log.get_channel_logic(channel_description); }); + } + log.get_logger_logic = get_logger_logic; + /** + */ + function format_entry(format_definition, entry) { + switch (format_definition.kind) { + case "jsonl": { + var now = Date.now(); + var timestamp = (now / 1000); + var datetime = (new Date(now)).toISOString(); + return (JSON.stringify({ + "datetime_timestamp": Math.round(timestamp), + "datetime_string": datetime /*.slice(0, 19)*/, + "level_numeric": entry.level, + "level_name": log.level_show(entry.level, { "abbreviated": false }), + "tags": entry.tags, + "incident": entry.incident, + "details": entry.details + }, undefined, (format_definition.data.structured + ? + "\t" + : + undefined))); + break; + } + case "human_readable": { + var parts = []; + parts.push(("<" + (new Date(Date.now())).toISOString() /*.slice(0, 19)*/ + ">")); + parts.push(("[" + log.level_show(entry.level, { "abbreviated": true }) + "]")); + for (var _i = 0, _a = entry.tags; _i < _a.length; _i++) { + var tag = _a[_i]; + parts.push(("{" + tag + "}")); + } + parts.push(entry.incident); + (entry.details !== null) && parts.push((": " + JSON.stringify(entry.details, undefined, undefined))); + return (parts.join(" ")); + break; + } + default: { + throw (new Error("unhandled format kind: " + format_definition["kind"])); + break; + } + } + } + log.format_entry = format_entry; + /** + */ + function parse_format_definition(format_definition_raw) { + return lib_plankton.call.distinguish((format_definition_raw !== null && format_definition_raw !== void 0 ? format_definition_raw : { + "kind": "human_readable", + "data": {} + }), { + "jsonl": function (_a) { + var structured = _a["structured"]; + return ({ + "kind": "jsonl", + "data": { + "structured": (structured !== null && structured !== void 0 ? structured : false) + } + }); + }, + "human_readable": function (data_) { return ({ + "kind": "human_readable", + "data": {} + }); } + }); + } + log.parse_format_definition = parse_format_definition; + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + var channel; + (function (channel) { + var filtered; + (function (filtered) { + /** + */ + function predicate_incident(substring) { + return (function (entry) { return entry.incident.includes(substring); }); + } + filtered.predicate_incident = predicate_incident; + /** + */ + function predicate_level(threshold) { + return (function (entry) { return log.level_order(threshold, entry.level); }); + } + filtered.predicate_level = predicate_level; + /** + */ + function predicate_tag(tag) { + return (function (entry) { return entry.tags.includes(tag); }); + } + filtered.predicate_tag = predicate_tag; + /** + * combines other predicates in disjunctive normal form + */ + function predicate_complex(definition) { + return (function (entry) { return definition.some(function (clause) { return clause.every(function (literal) { return (literal.item(entry) + === + literal.mode); }); }); }); + } + filtered.predicate_complex = predicate_complex; + /** + */ + function send(subject, entry) { + if (!subject.predicate(entry)) { + // do nothing + } + else { + subject.core.send(entry); + } + } + filtered.send = send; + /** + */ + function logic(subject) { + return { + "send": function (entry) { return send(subject, entry); } + }; + } + filtered.logic = logic; + })(filtered = channel.filtered || (channel.filtered = {})); + })(channel = log.channel || (log.channel = {})); + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + var channel; + (function (channel) { + var minlevel; + (function (minlevel) { + /** + */ + function to_filter_subject(subject) { + return { + "core": subject.core, + "predicate": lib_plankton.log.channel.filtered.predicate_level(subject.threshold) + }; + } + /** + */ + function send(subject, entry) { + lib_plankton.log.channel.filtered.send(to_filter_subject(subject), entry); + } + minlevel.send = send; + /** + */ + function logic(subject) { + return { + "send": function (entry) { return send(subject, entry); } + }; + } + minlevel.logic = logic; + })(minlevel = channel.minlevel || (channel.minlevel = {})); + })(channel = log.channel || (log.channel = {})); + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +/** + * output for writing log entries to web console + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + var channel; + (function (channel) { + var console_; + (function (console_) { + /** + * @todo tags + */ + function send(subject, entry) { + var _a; + var renderers = (_a = {}, + _a[log.enum_level.debug] = { + "renderer": function (i, d) { return console.log(i, d); }, + "show_level": true + }, + _a[log.enum_level.info] = { + "renderer": function (i, d) { return console.info(i, d); }, + "show_level": true + }, + _a[log.enum_level.notice] = { + "renderer": function (i, d) { return console.warn(i, d); }, + "show_level": true + }, + _a[log.enum_level.warning] = { + "renderer": function (i, d) { return console.warn(i, d); }, + "show_level": true + }, + _a[log.enum_level.error] = { + "renderer": function (i, d) { return console.error(i, d); }, + "show_level": true + }, + _a); + var setting = renderers[entry.level]; + setting.renderer(((setting.show_level + ? ("[" + log.level_show(entry.level) + "]" + " ") + : "") + + + ("" + entry.incident + "")), entry.details); + } + console_.send = send; + /** + */ + function logic(subject) { + return { + "send": function (entry) { return send(subject, entry); } + }; + } + console_.logic = logic; + })(console_ = channel.console_ || (channel.console_ = {})); + })(channel = log.channel || (log.channel = {})); + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:log« is free software: you can redistribute it and/or modify @@ -2656,82 +2713,367 @@ var lib_plankton; (function (log) { /** */ - var _channel_stack = null; - /** - * pushes a new configuration on the stack and activates it - */ - function conf_push(channels) { - if (_channel_stack === null) { - _channel_stack = []; - } - _channel_stack.push(channels); - } - log.conf_push = conf_push; - /** - * pops the current active configuration from the stack - */ - function conf_pop() { - if (_channel_stack.length > 0) { - _channel_stack.pop(); - } - else { - // do nothing + function get_channel_logic(channel_description) { + switch (channel_description.kind) { + default: { + throw (new Error("unhandled log channel kind: " + channel_description.kind)); + break; + } + case "filtered": { + return lib_plankton.log.channel.filtered.logic({ + "core": get_channel_logic(channel_description.data.core), + "predicate": lib_plankton.log.channel.filtered.predicate_complex(channel_description.data.predicate.map(function (clause_raw) { return clause_raw.map(function (literal_raw) { + var _a; + return ({ + "mode": ((_a = literal_raw["mode"]) !== null && _a !== void 0 ? _a : true), + "item": lib_plankton.call.distinguish(literal_raw["item"], { + "incident": function (_a) { + var substring = _a["substring"]; + if (substring === undefined) { + throw (new Error("required parameter missing: substring")); + } + else { + return lib_plankton.log.channel.filtered.predicate_incident(substring); + } + }, + "level": function (_a) { + var threshold = _a["threshold"]; + if (threshold === undefined) { + throw (new Error("required parameter missing: threshold")); + } + else { + return lib_plankton.log.channel.filtered.predicate_level(log.level_decode(threshold)); + } + }, + "tag": function (_a) { + var value = _a["value"]; + if (value === undefined) { + throw (new Error("required parameter missing: value")); + } + else { + return lib_plankton.log.channel.filtered.predicate_tag(value); + } + } + }, { + "fallback": function () { return function (entry) { return true; }; } + }) + }); + }); })) + }); + break; + } + case "minlevel": { + return lib_plankton.log.channel.minlevel.logic({ + "core": get_channel_logic(channel_description.data.core), + "threshold": log.level_decode(channel_description.data.threshold) + }); + break; + } + case "console": { + return lib_plankton.log.channel.console_.logic({}); + break; + } } } - log.conf_pop = conf_pop; + log.get_channel_logic = get_channel_logic; + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { /** - * makes the logging system ready */ - function setup() { - if (_channel_stack === null) { - _channel_stack = []; - conf_push(log.conf_default()); - } - else { - // do nothing - } + function default_logger() { + return [ + { + "kind": "minlevel", + "data": { + "core": { + "kind": "console", + "data": {} + }, + "threshold": "info" + } + }, + ]; + } + log.default_logger = default_logger; + })(log = lib_plankton.log || (lib_plankton.log = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:log«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:log« 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:lang« 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:log«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var log; + (function (log) { + /** + */ + var _main_logger_data = null; + /** + */ + function set_main_logger(logger_data) { + _main_logger_data = logger_data; + } + log.set_main_logger = set_main_logger; + /** + */ + function get_main_logger() { + return (_main_logger_data !== null && _main_logger_data !== void 0 ? _main_logger_data : log.default_logger()); } /** - * consumes a log entry, i.e. sends it to the currently active outputs */ - function add(entry) { - setup(); - _channel_stack.slice(-1)[0].forEach(function (channel) { return channel.add(entry); }); + function get_main_logger_logic() { + return lib_plankton.log.get_logger_logic(get_main_logger()); } - log.add = add; /** + * consumes a log entry, i.e. sends it to all channels */ - function debug(incident, details) { - if (details === void 0) { details = {}; } - add({ "level": log.enum_level.debug, "incident": incident, "details": details }); + function send_(logger, entry) { + logger.forEach(function (channel) { return channel.send(entry); }); + } + log.send_ = send_; + /** + * [convenience] + * + * @todo rename to "send" + */ + function debug_(logger, incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + send_(logger, { + "level": log.enum_level.debug, + "incident": incident, + "tags": option_tags, + "details": option_details + }); + } + log.debug_ = debug_; + /** + * [convenience] + * + * @todo rename to "info" + */ + function info_(logger, incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + send_(logger, { + "level": log.enum_level.info, + "incident": incident, + "tags": option_tags, + "details": option_details + }); + } + log.info_ = info_; + /** + * [convenience] + * + * @todo rename to "notice" + */ + function notice_(logger, incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + send_(logger, { + "level": log.enum_level.notice, + "incident": incident, + "tags": option_tags, + "details": option_details + }); + } + log.notice_ = notice_; + /** + * [convenience] + * + * @todo rename to "warning" + */ + function warning_(logger, incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + send_(logger, { + "level": log.enum_level.warning, + "incident": incident, + "tags": option_tags, + "details": option_details + }); + } + log.warning_ = warning_; + /** + * [convenience] + * + * @todo rename to "error" + */ + function error_(logger, incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + send_(logger, { + "level": log.enum_level.error, + "incident": incident, + "tags": option_tags, + "details": option_details + }); + } + log.error_ = error_; + /** + * [convenience] + */ + function _send(entry) { + send_(get_main_logger_logic(), entry); + } + log._send = _send; + /** + * [convenience] + */ + function _debug(incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + debug_(get_main_logger_logic(), incident, { + "tags": option_tags, + "details": option_details + }); + } + log._debug = _debug; + /** + * [convenience] + */ + function _info(incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + info_(get_main_logger_logic(), incident, { + "tags": option_tags, + "details": option_details + }); + } + log._info = _info; + /** + * [convenience] + */ + function _notice(incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + notice_(get_main_logger_logic(), incident, { + "tags": option_tags, + "details": option_details + }); + } + log._notice = _notice; + /** + * [convenience] + */ + function _warning(incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + warning_(get_main_logger_logic(), incident, { + "tags": option_tags, + "details": option_details + }); + } + log._warning = _warning; + /** + * [convenience] + */ + function _error(incident, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["tags"], option_tags = _c === void 0 ? [] : _c, _d = _b["details"], option_details = _d === void 0 ? null : _d; + error_(get_main_logger_logic(), incident, { + "tags": option_tags, + "details": option_details + }); + } + log._error = _error; + /** + * [convenience] + * + * @deprecated use ._debug instead! + */ + function debug(incident, details, tags) { + if (details === void 0) { details = null; } + if (tags === void 0) { tags = []; } + _debug(incident, { + "details": details, + "tags": tags + }); } log.debug = debug; /** + * [convenience] + * + * @deprecated use ._info instead! */ - function info(incident, details) { - if (details === void 0) { details = {}; } - add({ "level": log.enum_level.info, "incident": incident, "details": details }); + function info(incident, details, tags) { + if (details === void 0) { details = null; } + if (tags === void 0) { tags = []; } + _info(incident, { + "details": details, + "tags": tags + }); } log.info = info; /** + * [convenience] + * + * @deprecated use ._notice instead! */ - function notice(incident, details) { - if (details === void 0) { details = {}; } - add({ "level": log.enum_level.notice, "incident": incident, "details": details }); + function notice(incident, details, tags) { + if (details === void 0) { details = null; } + if (tags === void 0) { tags = []; } + _notice(incident, { + "details": details, + "tags": tags + }); } log.notice = notice; /** + * [convenience] + * + * @deprecated use ._warning instead! */ - function warning(incident, details) { - if (details === void 0) { details = {}; } - add({ "level": log.enum_level.warning, "incident": incident, "details": details }); + function warning(incident, details, tags) { + if (details === void 0) { details = null; } + if (tags === void 0) { tags = []; } + _warning(incident, { + "details": details, + "tags": tags + }); } log.warning = warning; /** + * [convenience] + * + * @deprecated use ._error instead! */ - function error(incident, details) { - if (details === void 0) { details = {}; } - add({ "level": log.enum_level.error, "incident": incident, "details": details }); + function error(incident, details, tags) { + if (details === void 0) { details = null; } + if (tags === void 0) { tags = []; } + _error(incident, { + "details": details, + "tags": tags + }); } log.error = error; })(log = lib_plankton.log || (lib_plankton.log = {})); @@ -2739,7 +3081,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:string«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:string« is free software: you can redistribute it and/or modify @@ -2898,7 +3240,7 @@ var make_eml_body = (function () { /* This file is part of »bacterio-plankton:string«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:string« is free software: you can redistribute it and/or modify @@ -2945,6 +3287,7 @@ var lib_plankton; */ function generate(prefix = "string_") { if (index_is > index_max) { + lib_plankton.log.error("plankton.string.generate.out_of_valid_indices", null); throw (new Error("[string_generate] out of valid indices")); } else { @@ -2971,7 +3314,7 @@ var lib_plankton; * @return {Array} * @author fenris */ - function split(chain, separator = " ") { + function split(chain, separator) { if (chain.length == 0) { return []; } @@ -3175,11 +3518,16 @@ var lib_plankton; if (options.legacy) { const value = args[key]; const regexp_argument = new RegExp("\\${" + key + "}", "g"); - lib_plankton.log.debug("lib_plankton.string.coin", { - "key": key, - "regex": regexp_argument.toString(), - "value": value, - }); + /* + lib_plankton.log.debug( + "lib_plankton.string.coin", + { + "key": key, + "regex": regexp_argument.toString(), + "value": value, + } + ); + */ str = str.replace(regexp_argument, value); } } @@ -3187,11 +3535,16 @@ var lib_plankton; { const value = args[key]; const regexp_argument = new RegExp(options.open + key + options.close, "g"); - lib_plankton.log.debug("lib_plankton.string.coin", { - "key": key, - "regex": regexp_argument.toString(), - "value": value, - }); + /* + lib_plankton.log.debug( + "lib_plankton.string.coin", + { + "key": key, + "regex": regexp_argument.toString(), + "value": value, + } + ); + */ str = str.replace(regexp_argument, value); } }); @@ -3235,6 +3588,12 @@ var lib_plankton; return slices; } string.slice = slice; + /** + */ + function capitalize(str) { + return (str[0].toUpperCase() + str.slice(1)); + } + string.capitalize = capitalize; })(string = lib_plankton.string || (lib_plankton.string = {})); })(lib_plankton || (lib_plankton = {})); /** @@ -3259,7 +3618,7 @@ var lib_string; /* This file is part of »bacterio-plankton:string«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:string« is free software: you can redistribute it and/or modify @@ -3523,7 +3882,7 @@ var printf = lib_plankton.string.printf; /* This file is part of »bacterio-plankton:string«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:string« is free software: you can redistribute it and/or modify @@ -3655,7 +4014,7 @@ var make_logger = (function () { /* This file is part of »bacterio-plankton:object«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:object« is free software: you can redistribute it and/or modify @@ -3677,128 +4036,136 @@ var lib_plankton; (function (object_1) { /** * @author fenris + * @deprecated use the "??" operator instead */ - function fetch(object, fieldname, fallback, escalation) { - if (fallback === void 0) { fallback = null; } - if (escalation === void 0) { escalation = 1; } - if ((fieldname in object) && (object[fieldname] !== undefined)) { + function fetch(object, fieldname, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "fallback": null, + "escalation": 1 + }, options); + if ((fieldname in object) + && + (object[fieldname] !== undefined)) { return object[fieldname]; } else { - switch (escalation) { - case 0: { - return fallback; - break; - } - case 1: { - var message = ("field '".concat(fieldname, "' not in structure")); - message += ("; using fallback value '".concat(String(fallback), "'")); - // console.warn(message); - return fallback; - break; - } - case 2: { - var message = ("field '".concat(fieldname, "' not in structure")); - throw (new Error(message)); - break; - } - default: { - throw (new Error("invalid escalation level ".concat(escalation))); - break; - } + if (!options.escalate) { + return options.fallback; + } + else { + throw (new Error("field '" + fieldname + "' not in structure")); } } } object_1.fetch = fetch; /** - * @author fenris */ function map(object_from, transformator) { - var object_to = {}; - Object.keys(object_from).forEach(function (key) { return (object_to[key] = transformator(object_from[key], key)); }); - return object_to; + return (Object.fromEntries(Object.entries(object_from) + .map(function (_a) { + var key = _a[0], value = _a[1]; + return ([key, transformator(value, key)]); + }))); } object_1.map = map; /** - * @desc gibt ein Objekt mit bestimmten Einträgen des Eingabe-Objekts zurück - * @author fenris + * gibt ein Objekt mit bestimmten Einträgen des Eingabe-Objekts zurück */ function filter(object_from, predicate) { - var object_to = {}; - Object.keys(object_from).forEach(function (key) { - var value = object_from[key]; - if (predicate(value, key)) { - object_to[key] = value; - } - }); - return object_to; + return (Object.fromEntries(Object.entries(object_from) + .filter(function (_a) { + var key = _a[0], value = _a[1]; + return predicate(value, key); + }))); } object_1.filter = filter; /** - * @desc wandelt ein Array mit Einträgen der Form {key,value} in ein entsprechendes Objekt um - * @author fenris + * wandelt ein Array mit Einträgen der Form {key,value} in ein entsprechendes Objekt um + * + * @deprecated use Object.fromEntries instead! */ function from_array(array) { - var object = {}; - array.forEach(function (entry) { return (object[entry.key] = entry.value); }); - return object; + return (Object.fromEntries(array + .map(function (_a) { + var key = _a["key"], value = _a["value"]; + return ([key, value]); + }))); } object_1.from_array = from_array; /** - * @desc wandelt ein Objekt in ein entsprechendes Array mit Einträgen der Form {key,value} um - * @author fenris + * wandelt ein Objekt in ein entsprechendes Array mit Einträgen der Form {key,value} um + * + * @deprecated use Object.entries insetad! */ function to_array(object) { - var array = []; - Object.keys(object).forEach(function (key) { return array.push({ "key": key, "value": object[key] }); }); - return array; + return (Object.entries(object) + .map(function (_a) { + var key = _a[0], value = _a[1]; + return ({ "key": key, "value": value }); + })); } object_1.to_array = to_array; /** - * @desc gibt eine Liste von Schlüsseln eines Objekts zurück - * @author fenris + * gibt eine Liste von Schlüsseln eines Objekts zurück + * + * @deprecated use Object.keys instead! */ function keys(object) { return Object.keys(object); } object_1.keys = keys; /** - * @desc gibt eine Liste von Werten eines Objekts zurück - * @author fenris + * gibt eine Liste von Werten eines Objekts zurück + * + * @deprecated use Object.values instead! */ function values(object) { - return to_array(object).map(function (entry) { return entry.value; }); + return Object.values(object); } object_1.values = values; /** - * @desc liest ein Baum-artiges Objekt an einer bestimmten Stelle aus - * @author fenris + * liest ein Baum-artiges Objekt an einer bestimmten Stelle aus */ - function path_read(object, path, fallback, escalation) { - if (fallback === void 0) { fallback = null; } - if (escalation === void 0) { escalation = 1; } + function path_read(object, path, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "fallback": null, + "escalate": false + }, options); var steps = ((path.length == 0) ? [] : path.split(".")); if (steps.length == 0) { throw (new Error("empty path")); } else { var position_1 = object; - var reachable = (position_1 != null) && steps.slice(0, steps.length - 1).every(function (step) { - position_1 = lib_plankton.object.fetch(position_1, step, null, 0); - return (position_1 != null); - }); + var reachable = ((position_1 != null) + && + (steps.slice(0, steps.length - 1) + .every(function (step) { + position_1 = lib_plankton.object.fetch(position_1, step, { + "fallback": null, + "escalate": false + }); + return (position_1 != null); + }))); if (reachable) { - return lib_plankton.object.fetch(position_1, steps[steps.length - 1], fallback, escalation); + return lib_plankton.object.fetch(position_1, steps[steps.length - 1], { + "fallback": options.fallback, + "escalate": options.escalate + }); } else { - return lib_plankton.object.fetch({}, "_dummy_", fallback, escalation); + return lib_plankton.object.fetch({}, "_dummy_", { + "fallback": options.fallback, + "escalate": options.escalate + }); } } } object_1.path_read = path_read; /** - * @desc schreibt einen Wert an eine bestimmte Stelle in einem Baum-artigen Objekt - * @author fenris + * schreibt einen Wert an eine bestimmte Stelle in einem Baum-artigen Objekt */ function path_write(object, path, value, construct) { if (construct === void 0) { construct = true; } @@ -3809,7 +4176,10 @@ var lib_plankton; else { var position_2 = object; var reachable = steps.slice(0, steps.length - 1).every(function (step) { - var position_ = lib_plankton.object.fetch(position_2, step, null, 0); + var position_ = lib_plankton.object.fetch(position_2, step, { + "fallback": null, + "escalate": false + }); if (position_ == null) { if (construct) { position_2[step] = {}; @@ -3829,99 +4199,111 @@ var lib_plankton; position_2[steps[steps.length - 1]] = value; } else { - var message = ("path '".concat(path, "' does not exist and may not be constructed")); - throw (new Error(message)); + throw (new Error("path '" + path + "' does not exist and may not be constructed")); } } } object_1.path_write = path_write; /** - * @desc prüft ob ein Objekt einem bestimmten Muster entspricht - * @param {Object} object das zu prüfende Objekt - * @param {Object} pattern das einzuhaltende Muster - * @param {Function} connlate eine Funktion zum Feststellen der Gleichheit von Einzelwerten - * @author fenris + * prüft ob ein Objekt einem bestimmten Muster entspricht + * + * @deprecated not very useful */ - function matches(object, pattern, collate) { - if (collate === void 0) { collate = instance_collate; } - return Object.keys(pattern).every(function (key) { return collate(pattern[key], object[key]); }); + function matches(object, pattern, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "collate": instance_collate + }, options); + return (Object.entries(pattern) + .every(function (_a) { + var key = _a[0], value = _a[1]; + return options.collate(value, object[key]); + })); } object_1.matches = matches; /** - * @desc erzeugt eine Projektion eines Baum-artigen Objekts in ein Listen-artiges Objekt - * @param {string} [separator] welches Zeichen als Trenner zwischen zwei Pfad-Schritten verwendet werden soll - * @author fenris + * erzeugt eine Projektion eines Baum-artigen Objekts in ein Listen-artiges Objekt */ - function flatten(value, separator, key_for_element) { - if (separator === void 0) { separator = "."; } - if (key_for_element === void 0) { key_for_element = (function (index) { return ("element_" + index.toFixed(0)); }); } - var integrate = function (result, key_, value_) { - if (value_ == null) { - result[key_] = value_; + function flatten(value, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "separator": ".", + "key_for_array_element": (function (index) { return ("element_" + index.toFixed(0)); }) + }, options); + var integrate = function (result, key, value) { + if (value == null) { + result[key] = value; } else { // primitive Werte direkt übernehmen - if (typeof (value_) != "object") { - result[key_] = value_; + if (typeof (value) != "object") { + result[key] = value; } // sonst durch rekursiven Aufruf die flache Variante des Wertes ermitteln und einarbeiten else { - var result_1 = flatten(value_); - Object.keys(result_1) - .forEach(function (key__) { - var value__ = result_1[key__]; - var key_new = (key_ + separator + key__); - result[key_new] = value__; + var result_ = flatten(value, { + "separator": options.separator, + "key_for_array_element": options.key_for_array_element + }); + Object.entries(result_).forEach(function (_a) { + var key_ = _a[0], value_ = _a[1]; + result[(key + options.separator + key_)] = value_; }); } } }; - if ((value === null) || (value === undefined)) { + if ((value === null) + || + (value === undefined)) { return null; } else { - var result_2 = {}; + var result_1 = {}; if (typeof (value) != "object") { - result_2["value"] = value; + result_1["value"] = value; } else { if (value instanceof Array) { - var array = (value); - array - .forEach(function (element, index) { - integrate(result_2, key_for_element(index), element); + value.forEach(function (element, index) { + integrate(result_1, options.key_for_array_element(index), element); }); } else { - var object_2 = (value); - Object.keys(object_2) - .forEach(function (key) { - integrate(result_2, key, object_2[key]); + Object.entries(value).forEach(function (_a) { + var key = _a[0], value = _a[1]; + integrate(result_1, key, value); }); } } - return result_2; + return result_1; } } object_1.flatten = flatten; /** - * @author fenris + * @deprecated use Object.assign instead! */ - function clash(x, y, _a) { - var _b = _a === void 0 ? {} : _a, _c = _b["overwrite"], overwrite = _c === void 0 ? true : _c, _d = _b["hooks"], _e = _d === void 0 ? {} : _d, _f = _e["existing"], hook_existing = _f === void 0 ? null : _f; - if (hook_existing == null) { - (function (key, value_old, value_new) { return console.warn("field ".concat(key, " already defined")); }); - } + function clash(x, y, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "overwrite": true, + "hooks": { + "existing": function (key, value_old, value_new) { + lib_plankton.log.warning("object_clash_field_already_defined", { + "key": key + }); + } + } + }, options); var z = {}; Object.keys(x).forEach(function (key) { z[key] = x[key]; }); Object.keys(y).forEach(function (key) { if (key in z) { - if (hook_existing != null) { - hook_existing(key, z[key], y[key]); + if (options.hooks.existing != null) { + options.hooks.existing(key, z[key], y[key]); } - if (overwrite) { + if (options.overwrite) { z[key] = y[key]; } } @@ -3933,24 +4315,39 @@ var lib_plankton; } object_1.clash = clash; /** - * @author fenris + * @deprecated use Object.assign instead! */ - function patch(core, mantle, deep, path) { - if (deep === void 0) { deep = true; } - if (path === void 0) { path = null; } + function patch(core, mantle, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "deep": true, + "path": null + }, options); if (mantle == null) { - console.warn("mantle is null; core was", core); + lib_plankton.log.warning("object_patch_mantle_is_null", { + "core": core + }); } else { Object.keys(mantle).forEach(function (key) { - var path_ = ((path == null) ? key : "".concat(path, ".").concat(key)); + var path_ = ((options.path == null) + ? + key + : + (options.path + "." + key)); var value_mantle = mantle[key]; if (!(key in core)) { - if ((typeof (value_mantle) == "object") && (value_mantle != null) && deep) { + if ((typeof (value_mantle) == "object") + && + (value_mantle != null) + && + options.deep) { if (value_mantle instanceof Array) { core[key] = []; value_mantle.forEach(function (element) { - if ((typeof (element) == "object") && (element != null)) { + if ((typeof (element) == "object") + && + (element != null)) { var element_ = {}; patch(element_, element); core[key].push(element_); @@ -3962,7 +4359,10 @@ var lib_plankton; } else { core[key] = {}; - patch(core[key], value_mantle, deep, path_); + patch(core[key], value_mantle, { + "deep": options.deep, + "path": path_ + }); } } else { @@ -3972,17 +4372,29 @@ var lib_plankton; else { var value_core = core[key]; if (typeof (value_core) == typeof (value_mantle)) { - if ((typeof (value_mantle) == "object") && (value_mantle != null) && deep) { - patch(core[key], value_mantle, deep, path_); + if ((typeof (value_mantle) == "object") + && + (value_mantle != null) + && + options.deep) { + patch(core[key], value_mantle, { + "deep": options.deep, + "path": path_ + }); } else { core[key] = value_mantle; } } else { - if ((value_core != null) && (value_mantle != null)) { - var message = "objects have different shapes at path '".concat(path_, "'; core has type '").concat(typeof (value_core), "' and mantle has type '").concat(typeof (value_mantle), "'"); - console.warn(message); + if ((value_core != null) + && + (value_mantle != null)) { + lib_plankton.log.warning("object_path_different_shapes", { + "path": path_, + "core_type": typeof (value_core), + "mantle_type": typeof (value_mantle) + }); } core[key] = value_mantle; // throw (new Error(message)); @@ -3993,23 +4405,26 @@ var lib_plankton; } object_1.patch = patch; /** - * @author fenris + * @deprecated use Object.assign instead! */ - function patched(core, mantle, deep) { - if (deep === void 0) { deep = undefined; } + function patched(core, mantle, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "deep": true + }, options); var result = {}; - patch(result, core, deep); - patch(result, mantle, deep); + patch(result, core, { "deep": options.deep }); + patch(result, mantle, { "deep": options.deep }); return result; } object_1.patched = patched; /** - * @author fenris + * @deprecated use Object.assign instead! */ function attached(object, key, value) { var mantle = {}; mantle[key] = value; - return patched(object, mantle, false); + return patched(object, mantle, { "deep": false }); } object_1.attached = attached; /** @@ -4024,7 +4439,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:translate«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:translate« is free software: you can redistribute it and/or modify @@ -4122,7 +4537,9 @@ var lib_plankton; function feed(package_) { let identifier = package_.meta.identifier; if (identifier in _packages) { - lib_plankton.object.patch(_packages[identifier].tree, package_.tree, true); + lib_plankton.object.patch(_packages[identifier].tree, package_.tree, { + "deep": true, + }); } else { if (translate._verbosity >= 2) { @@ -4289,7 +4706,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:translate«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:translate« is free software: you can redistribute it and/or modify @@ -4367,7 +4784,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:database«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:database« is free software: you can redistribute it and/or modify @@ -4403,7 +4820,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:storage«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4422,7 +4839,7 @@ along with »bacterio-plankton:storage«. If not, see »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4441,7 +4858,7 @@ along with »bacterio-plankton:storage«. If not, see »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4551,7 +4968,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:storage«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4595,7 +5012,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:storage«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4720,7 +5137,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:storage«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:storage« is free software: you can redistribute it and/or modify @@ -4767,9 +5184,1072 @@ var lib_plankton; })(storage = lib_plankton.storage || (lib_plankton.storage = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:map«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:map« 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:map« 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:map«. If not, see . + */ +/* +This file is part of »bacterio-plankton:map«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:map« 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:map« 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:map«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var map; + (function (map_1) { + /** + */ + function clear(map) { + map.iterate(function (value, key) { + map["delete"](key); + }); + } + map_1.clear = clear; + /** + */ + function keys(map) { + var keys = []; + map.iterate(function (value, key) { + keys.push(key); + }); + return keys; + } + map_1.keys = keys; + /** + */ + function values(map) { + var values = []; + map.iterate(function (value, key) { + values.push(value); + }); + return values; + } + map_1.values = values; + /** + */ + function dump(map) { + var pairs = []; + map.iterate(function (value, key) { + pairs.push({ "key": key, "value": value }); + }); + return pairs; + } + map_1.dump = dump; + /** + */ + function show(map, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "show_key": instance_show, + "show_value": instance_show + }, options); + return ("[" + + + (dump(map) + .map(function (_a) { + var key = _a["key"], value = _a["value"]; + return (options.show_key(key) + + + " -> " + + + options.show_value(value)); + }) + .join(", ")) + + + "]"); + } + map_1.show = show; + })(map = lib_plankton.map || (lib_plankton.map = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:map«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:map« 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:map« 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:map«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var map; + (function (map) { + var simplemap; + (function (simplemap) { + /** + */ + function make(options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "data": {} + }, options); + return { + "data": options.data + }; + } + simplemap.make = make; + /** + */ + function size(subject) { + return Object.keys(subject.data).length; + } + simplemap.size = size; + /** + */ + function has(subject, key) { + return (key in subject.data); + } + simplemap.has = has; + /** + */ + function get_safe(subject, key) { + if (key in subject.data) { + return lib_plankton.pod.make_filled(subject.data[key]); + } + else { + return lib_plankton.pod.make_empty(); + } + } + simplemap.get_safe = get_safe; + /** + */ + function get(subject, key, fallback) { + if (fallback === void 0) { fallback = lib_plankton.pod.make_empty(); } + if (key in subject.data) { + return subject.data[key]; + } + else { + if (!lib_plankton.pod.is_filled(fallback)) { + throw (new Error("key not found")); + } + else { + return lib_plankton.pod.cull(fallback); + } + } + } + simplemap.get = get; + /** + */ + function set(subject, key, value) { + subject.data[key] = value; + } + simplemap.set = set; + /** + */ + function delete_(subject, key) { + delete subject.data[key]; + } + simplemap.delete_ = delete_; + /** + */ + function iterate(subject, procedure) { + Object.entries(subject.data).forEach(function (_a) { + var key = _a[0], value = _a[1]; + procedure(value, key); + }); + } + simplemap.iterate = iterate; + /** + */ + function implementation_map(subject) { + return { + "size": function () { return size(subject); }, + "has": function (key) { return has(subject, key); }, + "get": function (key, fallback) { return get(subject, key, fallback); }, + "set": function (key, value) { return set(subject, key, value); }, + "delete": function (key) { return delete_(subject, key); }, + "iterate": function (function_) { return iterate(subject, function_); } + }; + } + simplemap.implementation_map = implementation_map; + })(simplemap = map.simplemap || (map.simplemap = {})); + })(map = lib_plankton.map || (lib_plankton.map = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:map«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:map« 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:map« 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:map«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var map; + (function (map) { + var hashmap; + (function (hashmap) { + /** + */ + function make(hashing, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "pairs": [] + }, options); + var subject = { + "hashing": hashing, + "core": lib_plankton.map.simplemap.make({}) + }; + options.pairs.forEach(function (pair) { + set(subject, pair.key, pair.value); + }); + return subject; + } + hashmap.make = make; + /** + */ + function size(subject) { + return lib_plankton.map.simplemap.size(subject.core); + } + hashmap.size = size; + /** + */ + function has(subject, key) { + return lib_plankton.map.simplemap.has(subject.core, subject.hashing(key)); + } + hashmap.has = has; + /** + */ + function get(subject, key, fallback) { + if (fallback === void 0) { fallback = lib_plankton.pod.make_empty(); } + /* + we have to adjust the fallback argument, so that it can be used in our underlying simplemap core + therefore we pack the value together with any key as dummy + */ + return (lib_plankton.map.simplemap.get(subject.core, subject.hashing(key), lib_plankton.pod.propagate(fallback, function (value) { return ({ + "key": key, + "value": value + }); })) + .value); + } + hashmap.get = get; + /** + */ + function set(subject, key, value) { + var key_ = subject.hashing(key); + return (lib_plankton.map.simplemap.set(subject.core, key_, { "key": key, "value": value })); + } + hashmap.set = set; + /** + */ + function delete_(subject, key) { + return (lib_plankton.map.simplemap.delete_(subject.core, subject.hashing(key))); + } + hashmap.delete_ = delete_; + /** + */ + function iterate(subject, procedure) { + return (lib_plankton.map.simplemap.iterate(subject.core, function (_a, key_) { + var key = _a["key"], value = _a["value"]; + procedure(value, key); + })); + } + hashmap.iterate = iterate; + /** + */ + function implementation_map(subject) { + return { + "size": function () { return size(subject); }, + "has": function (key) { return has(subject, key); }, + "get": function (key, fallback) { return get(subject, key, fallback); }, + "set": function (key, value) { return set(subject, key, value); }, + "delete": function (key) { return delete_(subject, key); }, + "iterate": function (procedure) { return iterate(subject, procedure); } + }; + } + hashmap.implementation_map = implementation_map; + })(hashmap = map.hashmap || (map.hashmap = {})); + })(map = lib_plankton.map || (lib_plankton.map = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:map«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:map« 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:map« 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 +3GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with »bacterio-plankton:map«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var map; + (function (map) { + var collatemap; + (function (collatemap) { + /** + */ + function make(collation, options) { + if (options === void 0) { options = {}; } + options = Object.assign({ + "pairs": [] + }, options); + var subject = { + "collation": collation, + "pairs": [] + }; + options.pairs.forEach(function (pair) { + set(subject, pair.key, pair.value); + }); + return subject; + } + collatemap.make = make; + /** + */ + function size(subject) { + return subject.pairs.length; + } + collatemap.size = size; + /** + */ + function has(subject, key) { + return (subject.pairs.some(function (pair) { return subject.collation(key, pair.key); })); + } + collatemap.has = has; + /** + * @todo use .find + */ + function get(subject, key, fallback) { + var value; + var found = (subject.pairs + .some(function (pair) { + if (subject.collation(key, pair.key)) { + value = pair.value; + return true; + } + else { + return false; + } + })); + if (found) { + return value; + } + else { + if (!lib_plankton.pod.is_filled(fallback)) { + throw (new Error("key not found")); + } + else { + return lib_plankton.pod.cull(fallback); + } + } + } + collatemap.get = get; + /** + */ + function set(subject, key, value) { + var found = (subject.pairs + .some(function (pair) { + if (subject.collation(key, pair.key)) { + // pair.value = value; + return true; + } + else { + return false; + } + })); + if (found) { + // nothing + } + else { + subject.pairs.push({ + "key": key, + "value": value + }); + } + } + collatemap.set = set; + /** + */ + function delete_(subject, key) { + var index; + var found = (subject.pairs + .some(function (pair, index_) { + if (subject.collation(key, pair.key)) { + index = index_; + return true; + } + else { + return false; + } + })); + if (found) { + subject.pairs.splice(index, 1); + } + else { + // do nothing + } + } + collatemap.delete_ = delete_; + /** + */ + function iterate(subject, function_) { + subject.pairs + .forEach(function (pair) { + function_(pair.value, pair.key); + }); + } + collatemap.iterate = iterate; + /** + */ + function implementation_map(subject) { + return { + "size": function () { return size(subject); }, + "has": function (key) { return has(subject, key); }, + "get": function (key, fallback) { return get(subject, key, fallback); }, + "set": function (key, value) { return set(subject, key, value); }, + "delete": function (key) { return delete_(subject, key); }, + "iterate": function (function_) { return iterate(subject, function_); } + }; + } + collatemap.implementation_map = implementation_map; + })(collatemap = map.collatemap || (map.collatemap = {})); + })(map = lib_plankton.map || (lib_plankton.map = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:pit«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:pit« 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:pit« 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:pit«. If not, see . + */ +/* +This file is part of »bacterio-plankton:pit«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:pit« 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:pit« 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:pit«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var pit; + (function (pit_1) { + /** + * @todo complete + */ + function timezone_name_to_timezone_shift(timezone_name) { + const map = { + "UTC": 0, + "CET": +1, + "CEST": +2, + }; + if (!(timezone_name in map)) { + throw (new Error("unhandled timezone: " + timezone_name)); + } + else { + return map[timezone_name]; + } + } + pit_1.timezone_name_to_timezone_shift = timezone_name_to_timezone_shift; + /** + */ + function date_object_get_week_of_year(date) { + let date_ = new Date(date.getTime()); + date_.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date_.setDate(date_.getDate() + 3 - (date_.getDay() + 6) % 7); + // January 4 is always in week 1. + let week1 = new Date(date_.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week1. + return (1 + + + Math.round((((date_.getTime() - week1.getTime()) / 86400000) + - + 3 + + + (week1.getDay() + 6) % 7) + / + 7)); + } + pit_1.date_object_get_week_of_year = date_object_get_week_of_year; + /** + */ + function to_unix_timestamp(pit) { + return pit; + } + pit_1.to_unix_timestamp = to_unix_timestamp; + /** + */ + function from_unix_timestamp(unix_timestamp) { + return unix_timestamp; + } + pit_1.from_unix_timestamp = from_unix_timestamp; + /** + */ + function to_date_object(pit) { + return (new Date(pit * 1000)); + } + pit_1.to_date_object = to_date_object; + /** + */ + function from_date_object(date_object) { + return Math.round(date_object.getTime() / 1000); + } + /** + * @todo test + */ + function to_datetime(pit, { "timezone_shift": option_timezone_shift = 0, } = {}) { + return lib_plankton.call.convey(pit, [ + to_date_object, + (x) => x.getTime(), + (x) => (x + ((option_timezone_shift * (60 * 60)) * 1000)), + (x) => new Date(x), + x => x.toISOString(), + x => ({ + "timezone_shift": option_timezone_shift, + "date": { + "year": parseInt(x.slice(0, 4)), + "month": parseInt(x.slice(5, 7)), + "day": parseInt(x.slice(8, 10)), + }, + "time": { + "hour": parseInt(x.slice(11, 13)), + "minute": parseInt(x.slice(14, 16)), + "second": parseInt(x.slice(17, 19)), + }, + }) + ]); + } + pit_1.to_datetime = to_datetime; + /** + */ + function from_datetime(datetime) { + return lib_plankton.call.convey(datetime, [ + (x) => lib_plankton.string.coin("{{year}}-{{month}}-{{day}}T{{hour}}:{{minute}}:{{second}}.000+{{shift}}", { + "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"), + "hour": ((x.time !== null) ? x.time.hour : 0).toFixed(0).padStart(2, "0"), + "minute": ((x.time !== null) ? x.time.minute : 0).toFixed(0).padStart(2, "0"), + "second": ((x.time !== null) ? x.time.second : 0).toFixed(0).padStart(2, "0"), + "shift": (x.timezone_shift.toFixed(0).padStart(2, "0") + ":00"), + }), + x => (new Date(x)), + from_date_object, + ]); + } + pit_1.from_datetime = from_datetime; + /** + */ + function is_before(pit, reference) { + return (pit < reference); + } + pit_1.is_before = is_before; + /** + */ + function is_after(pit, reference) { + return (pit > reference); + } + /** + */ + function is_between(pit, reference_left, reference_right) { + return (is_after(pit, reference_left) + && + is_before(pit, reference_right)); + } + pit_1.is_between = is_between; + /** + */ + function shift_hour(pit, increment) { + return (pit + (60 * 60 * increment)); + } + /** + */ + function shift_day(pit, increment) { + return (pit + (60 * 60 * 24 * increment)); + } + pit_1.shift_day = shift_day; + /** + */ + function shift_week(pit, increment) { + return (pit + (60 * 60 * 24 * 7 * increment)); + } + pit_1.shift_week = shift_week; + /** + */ + function shift_year(pit, increment) { + return (pit + (60 * 60 * 24 * 365 * increment)); + } + /** + */ + function trunc_minute(pit) { + const datetime_input = to_datetime(pit); + const datetime_output = { + "timezone_shift": 0, + "date": { + "year": datetime_input.date.year, + "month": datetime_input.date.month, + "day": datetime_input.date.day, + }, + "time": { + "hour": ((datetime_input.time === null) + ? + 0 + : + datetime_input.time.hour), + "minute": ((datetime_input.time === null) + ? + 0 + : + datetime_input.time.minute), + "second": 0, + }, + }; + return from_datetime(datetime_output); + } + /** + */ + function trunc_hour(pit) { + const datetime_input = to_datetime(pit); + const datetime_output = { + "timezone_shift": 0, + "date": { + "year": datetime_input.date.year, + "month": datetime_input.date.month, + "day": datetime_input.date.day, + }, + "time": { + "hour": ((datetime_input.time === null) + ? + 0 + : + datetime_input.time.hour), + "minute": 0, + "second": 0, + }, + }; + return from_datetime(datetime_output); + } + /** + */ + function trunc_day(pit) { + const datetime_input = to_datetime(pit); + const datetime_output = { + "timezone_shift": 0, + "date": { + "year": datetime_input.date.year, + "month": datetime_input.date.month, + "day": datetime_input.date.day, + }, + "time": { + "hour": 0, + "minute": 0, + "second": 0, + }, + }; + return from_datetime(datetime_output); + } + /** + */ + function trunc_week(pit) { + const date_object = to_date_object(pit); + return lib_plankton.call.convey(date_object.getDay(), [ + (x) => ((x === 0) ? 7 : x), + (x) => (x - 1), + (x) => shift_day(pit, (-x)), + trunc_day + ]); + } + pit_1.trunc_week = trunc_week; + /** + */ + function trunc_month(pit) { + const datetime_input = to_datetime(pit); + const datetime_output = { + "timezone_shift": 0, + "date": { + "year": datetime_input.date.year, + "month": datetime_input.date.month, + "day": 1, + }, + "time": { + "hour": 0, + "minute": 0, + "second": 0, + }, + }; + return from_datetime(datetime_output); + } + /** + */ + function trunc_year(pit) { + const datetime_input = to_datetime(pit); + const datetime_output = { + "timezone_shift": 0, + "date": { + "year": datetime_input.date.year, + "month": 1, + "day": 1, + }, + "time": { + "hour": 0, + "minute": 0, + "second": 0, + }, + }; + return from_datetime(datetime_output); + } + /** + */ + function now() { + return from_date_object(new Date(Date.now())); + } + pit_1.now = now; + /** + * @param year year according to specified timezone shift + * @param week week according to specified timezone shift + * @return the begin of the week (monday, 00:00) + */ + function from_ywd(ywd, { "timezone_shift": option_timezone_shift = 0, } = {}) { + return lib_plankton.call.convey({ + "timezone_shift": option_timezone_shift, + "date": { + "year": ywd.year, + "month": 1, + "day": 1, + }, + "time": { + "hour": 0, + "minute": 0, + "second": 0 + } + }, [ + from_datetime, + (x) => shift_week(x, (ywd.week - 1)), + trunc_week, + (x) => shift_day(x, (ywd.day - 1)), + ]); + } + pit_1.from_ywd = from_ywd; + /** + * @todo timezone + */ + function to_ywd(pit, { "timezone_shift": option_timezone_shift = 0, } = {}) { + return lib_plankton.call.convey(pit, [ + to_date_object, + x => ({ + "year": x.getFullYear(), + "week": date_object_get_week_of_year(x), + "day": ((day => (day <= 0) ? 7 : day)(x.getDay())), + }) + ]); + } + pit_1.to_ywd = to_ywd; + /** + * computes the point in time for switching to central european summer time + * + * @todo write tests + */ + function cest_switch_on(year) { + return lib_plankton.call.convey(year, [ + (x) => ({ + "timezone_shift": 0, + "date": { + "year": x, + "month": 4, + "day": 1, + }, + "time": { + "hour": 2, + "minute": 0, + "second": 0 + }, + }), + from_datetime, + trunc_week, + x => shift_day(x, -1), + ]); + } + pit_1.cest_switch_on = cest_switch_on; + /** + * computes the point in time for switching away from central european summer time + * + * @todo write tests + */ + function cest_switch_off(year) { + return lib_plankton.call.convey(year, [ + (x) => ({ + "timezone_shift": 0, + "date": { + "year": x, + "month": 11, + "day": 1, + }, + "time": { + "hour": 1, + "minute": 0, + "second": 0 + }, + }), + from_datetime, + trunc_week, + x => shift_day(x, -1), + ]); + } + pit_1.cest_switch_off = cest_switch_off; + /** + */ + function timezone_shift_ce(pit) { + const year = to_datetime(pit).date.year; + return (is_between(pit, cest_switch_on(year), cest_switch_off(year)) + ? +2 + : +1); + } + pit_1.timezone_shift_ce = timezone_shift_ce; + /** + * [convenience] + */ + function to_datetime_ce(pit) { + return to_datetime(pit, { + "timezone_shift": timezone_shift_ce(pit), + }); + } + pit_1.to_datetime_ce = to_datetime_ce; + /** + */ + function datetime_translate(datetime, timezone_shift) { + if (datetime.timezone_shift === timezone_shift) { + return datetime; + } + else { + const pit = from_datetime(datetime); + const pit_shifted = shift_hour(pit, (timezone_shift - datetime.timezone_shift)); + const datetime_shifted = to_datetime(pit_shifted); + return { + "timezone_shift": timezone_shift, + "date": datetime_shifted.date, + "time": ((datetime.time === null) + ? + null + : datetime_shifted.time) + }; + } + } + pit_1.datetime_translate = datetime_translate; + /** + * [convenience] + */ + function datetime_translate_ce(datetime) { + return datetime_translate(datetime, timezone_shift_ce(from_datetime(datetime))); + } + pit_1.datetime_translate_ce = datetime_translate_ce; + /** + */ + function timezone_shift_format(timezone_shift) { + return lib_plankton.string.coin("{{sign}}{{value}}", { + "sign": ((timezone_shift === 0) + ? + " " + : + ((timezone_shift > 0) + ? + "+" + : + "-")), + "value": Math.abs(timezone_shift).toFixed(0), + }); + } + pit_1.timezone_shift_format = timezone_shift_format; + /** + */ + function date_format(date) { + return lib_plankton.string.coin("{{year}}-{{month}}-{{day}}", { + "year": date.year.toFixed(0).padStart(4, "0"), + "month": date.month.toFixed(0).padStart(2, "0"), + "day": date.day.toFixed(0).padStart(2, "0"), + }); + } + pit_1.date_format = date_format; + /** + */ + function time_format(time, { "show_seconds": option_show_seconds = false, } = {}) { + return lib_plankton.string.coin((option_show_seconds + ? + "{{hour}}:{{minute}}:{{seconds}}" + : + "{{hour}}:{{minute}}"), { + "hour": time.hour.toFixed(0).padStart(2, "0"), + "minute": time.minute.toFixed(0).padStart(2, "0"), + "second": time.second.toFixed(0).padStart(2, "0"), + }); + } + pit_1.time_format = time_format; + /** + * @todo show timezone + */ + function datetime_format(datetime, { "timezone_indicator": option_timezone_indicator = "", "show_timezone": option_show_timezone = false, "adjust_to_ce": option_adjust_to_ce = false, "omit_date": option_omit_date = false, } = {}) { + if (datetime === null) { + return "-"; + } + else { + const datetime_adjusted = (option_adjust_to_ce + ? + to_datetime_ce(from_datetime(datetime)) + : + datetime); + return lib_plankton.string.coin("{{macro_date_and_time}}{{macro_timezone}}", { + "macro_date_and_time": ([ + // date + (option_omit_date + ? + null + : + date_format(datetime_adjusted.date)), + // time + ((datetime_adjusted.time === null) + ? + null + : + time_format(datetime_adjusted.time)), + ] + .filter(x => (x !== null)) + .join(", ")), + "macro_timezone": (option_show_timezone + ? + lib_plankton.string.coin(" [{{timezone_indicator}}{{timezone_value}}]", { + "timezone_indicator": option_timezone_indicator, + "timezone_value": timezone_shift_format(datetime_adjusted.timezone_shift), + }) + : + ""), + }); + } + } + pit_1.datetime_format = datetime_format; + /** + */ + function timespan_format(from, to, { "timezone_indicator": option_timezone_indicator = "", "show_timezone": option_show_timezone = false, "adjust_to_ce": option_adjust_to_ce = false, "omit_date": option_omit_date = false, } = {}) { + const from_adjusted = (option_adjust_to_ce + ? + datetime_translate_ce(from) + : + from); + const to_adjusted = ((to === null) + ? + null + : + (option_adjust_to_ce + ? + datetime_translate_ce(to) + : + to)); + return lib_plankton.string.coin("{{from}}{{to_macro}}{{macro_timezone}}", { + "from": datetime_format(from_adjusted, { + "show_timezone": false, + "adjust_to_ce": false, + "omit_date": option_omit_date, + }), + "to_macro": ((to_adjusted === null) + ? + "" + : + lib_plankton.string.coin(" - {{to}}", { + "to": datetime_format(to_adjusted, { + "omit_date": ((from_adjusted.date.year === to_adjusted.date.year) + && + (from_adjusted.date.month === to_adjusted.date.month) + && + (from_adjusted.date.day === to_adjusted.date.day)) + }), + })), + "macro_timezone": (option_show_timezone + ? + lib_plankton.string.coin(" [{{timezone_indicator}}{{timezone_value}}]", { + "timezone_indicator": option_timezone_indicator, + "timezone_value": timezone_shift_format(from_adjusted.timezone_shift), + }) + : + ""), + }); + } + pit_1.timespan_format = timespan_format; + })(pit = lib_plankton.pit || (lib_plankton.pit = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -4788,7 +6268,7 @@ along with »bacterio-plankton:zoo-input«. If not, see »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -4846,7 +6326,110 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:zoo-input« 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-input« 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-input«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var zoo_input; + (function (zoo_input) { + /** + * @author fenris + */ + class class_input_soft { + /** + */ + constructor(core, options = {}) { + options = Object.assign({}, options); + this.core = core; + this.dom_set = null; + this.dom_wrapper = null; + } + /** + */ + toggle(also_element, mode) { + if (also_element) { + this.dom_set.checked = mode; + } + else { + // do nothing + } + this.dom_wrapper.classList.toggle("plankton_input_soft_inactive", (!mode)); + } + /** + * [implementation] + */ + async setup(parent) { + let dom_container = document.createElement("div"); + dom_container.classList.add("plankton_input_soft_container"); + { + // set + { + this.dom_set = document.createElement("input"); + this.dom_set.setAttribute("type", "checkbox"); + this.dom_set.classList.add("plankton_input_soft_setter"); + dom_container.appendChild(this.dom_set); + } + // core + { + this.dom_wrapper = document.createElement("div"); + this.dom_wrapper.classList.add("plankton_input_soft_core_wrapper"); + dom_container.appendChild(this.dom_wrapper); + await this.core.setup(this.dom_wrapper); + } + } + this.dom_set.addEventListener("change", (event) => { + this.toggle(false, event.target.checked); + }); + parent.appendChild(dom_container); + this.toggle(true, false); + return Promise.resolve(undefined); + } + /** + * [implementation] + */ + read() { + if (!this.dom_set.checked) { + return Promise.resolve(null); + } + else { + return this.core.read(); + } + } + /** + * [implementation] + */ + write(value) { + if (value === null) { + this.toggle(true, false); + return Promise.resolve(undefined); + } + else { + this.toggle(true, true); + return this.core.write(value); + } + } + } + zoo_input.class_input_soft = class_input_soft; + })(zoo_input = lib_plankton.zoo_input || (lib_plankton.zoo_input = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:zoo-input«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -4908,7 +6491,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5005,7 +6588,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5063,7 +6646,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5120,7 +6703,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5216,7 +6799,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5299,7 +6882,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5378,7 +6961,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5442,7 +7025,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5526,7 +7109,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5554,6 +7137,7 @@ var lib_plankton; */ constructor(element_input_factory, options = {}) { options = Object.assign({ + "read_only": false, "translations": { "add": "add", "remove": "remove", @@ -5562,6 +7146,7 @@ var lib_plankton; this.element_input_factory = element_input_factory; this.elements = []; this.elements_container_dom = null; + this.read_only = options.read_only; this.translations = options.translations; } /** @@ -5587,6 +7172,9 @@ var lib_plankton; remover_dom.classList.add("plankton_input_list_button"); remover_dom.classList.add("plankton_input_list_element_remover"); remover_dom.setAttribute("title", this.translations.remove); + if (this.read_only) { + remover_dom.setAttribute("disabled", "disabled"); + } remover_dom.textContent = "x"; remover_dom.addEventListener("click", (event) => { event.preventDefault(); @@ -5630,6 +7218,9 @@ var lib_plankton; adder_dom.classList.add("plankton_input_list_button"); adder_dom.classList.add("plankton_input_list_adder"); adder_dom.setAttribute("title", this.translations.add); + if (this.read_only) { + adder_dom.setAttribute("disabled", "disabled"); + } adder_dom.textContent = "+"; adder_dom.addEventListener("click", (event) => { event.preventDefault(); @@ -5673,7 +7264,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5731,7 +7322,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5800,7 +7391,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5880,7 +7471,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-input«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-input« is free software: you can redistribute it and/or modify @@ -5921,7 +7512,7 @@ var lib_plankton; async setup(parent) { let dom_group = document.createElement("div"); dom_group.classList.add("plankton_input_group"); - await Promise.all(this.fields.map(async (field) => { + for await (const field of this.fields) { let dom_field = document.createElement("div"); dom_field.classList.add("plankton_input_group_field"); dom_field.setAttribute("rel", field.name); @@ -5957,8 +7548,8 @@ var lib_plankton; field.input.setup(dom_field), ]); dom_group.appendChild(dom_field); - return Promise.resolve(undefined); - })); + // return Promise.resolve(undefined); + } parent.appendChild(dom_group); return Promise.resolve(undefined); } @@ -5985,9 +7576,252 @@ var lib_plankton; })(zoo_input = lib_plankton.zoo_input || (lib_plankton.zoo_input = {})); })(lib_plankton || (lib_plankton = {})); /* +This file is part of »bacterio-plankton:zoo-input«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:zoo-input« 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-input« 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-input«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var zoo_input; + (function (zoo_input) { + /** + */ + class class_input_hashmap { + /** + */ + constructor(hash_key, key_input_factory, value_input_factory) { + this.hash_key = hash_key; + this.core = new lib_plankton.zoo_input.class_input_list(() => new lib_plankton.zoo_input.class_input_group([ + { + "name": "key", + "input": key_input_factory(), + }, + { + "name": "value", + "input": value_input_factory(), + }, + ])); + } + /** + * [implementation] + */ + setup(parent) { + return this.core.setup(parent); + } + /** + * [implementation] + */ + async read() { + const pairs = await this.core.read(); + const map = lib_plankton.map.hashmap.implementation_map(lib_plankton.map.hashmap.make(this.hash_key, { + "pairs": pairs + })); + return Promise.resolve(map); + } + /** + * [implementation] + */ + async write(map) { + const pairs = lib_plankton.map.dump(map); + await this.core.write(pairs); + return Promise.resolve(undefined); + } + } + zoo_input.class_input_hashmap = class_input_hashmap; + })(zoo_input = lib_plankton.zoo_input || (lib_plankton.zoo_input = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:zoo-input«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:zoo-input« 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-input« 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-input«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var zoo_input; + (function (zoo_input) { + /** + */ + class class_input_datetime { + /** + */ + constructor(options = {}) { + options = Object.assign({ + "label_timezone_shift": "", + "label_date": "", + "label_time": "", + }, options); + this.core = new zoo_input.class_input_group([ + { + "name": "timezone_shift", + "input": new zoo_input.class_input_number(), + "label": options.label_timezone_shift, + }, + { + "name": "date", + "input": new zoo_input.class_input_date(), + "label": options.label_date, + }, + { + "name": "time", + "input": new zoo_input.class_input_soft(new zoo_input.class_input_time()), + "label": options.label_time, + }, + ]); + } + /** + */ + setup(parent) { + return this.core.setup(parent); + } + /** + */ + read() { + return this.core.read(); + } + /** + */ + write(value) { + return this.core.write(value); + } + } + zoo_input.class_input_datetime = class_input_datetime; + })(zoo_input = lib_plankton.zoo_input || (lib_plankton.zoo_input = {})); +})(lib_plankton || (lib_plankton = {})); +/* +This file is part of »bacterio-plankton:zoo-input«. + +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' + + +»bacterio-plankton:zoo-input« 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-input« 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-input«. If not, see . + */ +var lib_plankton; +(function (lib_plankton) { + var zoo_input; + (function (zoo_input) { + /** + * for central europe with daylight saving time feature + */ + class class_input_datetime_central_europe { + /** + */ + constructor(options = {}) { + options = Object.assign({ + "label_date": "", + "label_time": "", + }, options); + this.core = new zoo_input.class_input_group([ + { + "name": "date", + "input": new zoo_input.class_input_date(), + "label": options.label_date, + }, + { + "name": "time", + "input": new zoo_input.class_input_soft(new zoo_input.class_input_time()), + "label": options.label_time, + }, + ]); + } + /** + */ + setup(parent) { + return this.core.setup(parent); + } + /** + */ + async read() { + const datetime_easy = await this.core.read(); + const datetime_cet = { + "timezone_shift": 1, + "date": datetime_easy.date, + "time": datetime_easy.time, + }; + const datetime_cest = { + "timezone_shift": 2, + "date": datetime_easy.date, + "time": datetime_easy.time, + }; + const datetime = (lib_plankton.pit.is_between(lib_plankton.pit.from_datetime(datetime_cet), lib_plankton.pit.cest_switch_on(datetime_easy.date.year), lib_plankton.pit.cest_switch_off(datetime_easy.date.year)) + ? + datetime_cest + : + datetime_cet); + if (datetime_easy.time === null) { + datetime.time = null; + } + else { + // do nothing + } + return Promise.resolve(datetime); + } + /** + */ + async write(value) { + const pit = lib_plankton.pit.from_datetime(value); + const datetime_utc = lib_plankton.pit.to_datetime(pit, { + "timezone_shift": 0, + }); + const datetime_relative = lib_plankton.pit.to_datetime(pit, { + "timezone_shift": (lib_plankton.pit.is_between(lib_plankton.pit.from_datetime(datetime_utc), lib_plankton.pit.cest_switch_on(datetime_utc.date.year), lib_plankton.pit.cest_switch_off(datetime_utc.date.year)) + ? + 2 + : + 1) + }); + const datetime_easy = { + "date": datetime_relative.date, + "time": ((value.time === null) ? null : datetime_relative.time), + }; + return this.core.write(datetime_easy); + } + } + zoo_input.class_input_datetime_central_europe = class_input_datetime_central_europe; + })(zoo_input = lib_plankton.zoo_input || (lib_plankton.zoo_input = {})); +})(lib_plankton || (lib_plankton = {})); +/* This file is part of »bacterio-plankton:zoo-form«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-form« is free software: you can redistribute it and/or modify @@ -6155,7 +7989,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-form«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-form« is free software: you can redistribute it and/or modify @@ -6244,7 +8078,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-search«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-search« is free software: you can redistribute it and/or modify @@ -6430,7 +8264,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-editor«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-editor« is free software: you can redistribute it and/or modify @@ -6867,7 +8701,7 @@ var lib_plankton; /* This file is part of »bacterio-plankton:zoo-page«. -Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' +Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR' »bacterio-plankton:zoo-page« is free software: you can redistribute it and/or modify diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 13253d4..4e05eb9 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -69,6 +69,8 @@ "page.password_change_exec.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten", "page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", - "page.password_change_exec.status.success": "erledigt" + "page.password_change_exec.status.success": "erledigt", + "page.invite_list.title": "Einladungen", + "page.invite_handle.title": "Einladung" } } diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index b0f3b47..333b68c 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -69,6 +69,8 @@ "page.password_change_exec.flaw.password_lacks_number": "das Passwort muss ein Zahl beinhalten", "page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", - "page.password_change_exec.status.success": "done" + "page.password_change_exec.status.success": "done", + "page.invite_list.title": "Invites", + "page.invite_handle.title": "Invite" } } diff --git a/source/logic/backend.ts b/source/logic/backend.ts index 01446a9..e9ca607 100644 --- a/source/logic/backend.ts +++ b/source/logic/backend.ts @@ -485,20 +485,45 @@ namespace _espe.backend ); } - + + /** + */ + export async function invite_list( + ) : Promise< + Array< + { + id : int; + key : string; + expiry : (null | int); + name_value : string; + } + > + > + { + return abstract_call( + "GET", + lib_plankton.string.coin( + "/invite/list", + { + } + ) + ); + } + + /** */ export async function invite_examine( key : string ) : Promise< { - membership_number_mode : int; + membership_number_changeable : boolean; membership_number_value : (null | string); - name_mode : int; + name_changeable : boolean; name_value : string; - email_address_mode : int; + email_address_changeable : boolean; email_address_value : (null | string); - groups_mode : int; + groups_changeable : boolean; groups_value : Array; } > diff --git a/source/logic/main.ts b/source/logic/main.ts index 7ad3adf..b53ada6 100644 --- a/source/logic/main.ts +++ b/source/logic/main.ts @@ -69,6 +69,11 @@ function setup_nav( "label": "Anlegen", "classes": ["logged_in"], }, + { + "location": {"name": "invite_list", "parameters": {}}, + "label": "Einladungen", + "classes": ["logged_in"], + }, { "location": {"name": "logout", "parameters": {}}, "label": "Abmelden", diff --git a/source/pages/invite_handle/logic.ts b/source/pages/invite_handle/logic.ts index 2e7062e..6c253e8 100644 --- a/source/pages/invite_handle/logic.ts +++ b/source/pages/invite_handle/logic.ts @@ -21,18 +21,16 @@ lib_plankton.zoo_page.register( target_element.appendChild(template_request("invite_handle")); - /** - * @todo invite_handle-title - */ + target_element.querySelector(".invite_handle-title").textContent = lib_plankton.translate.get("page.invite_handle.title"); const data : { - membership_number_mode : int; + membership_number_changeable : boolean; membership_number_value : (null | string); - name_mode : int; + name_changeable : boolean; name_value : string; - email_address_mode : int; + email_address_changeable : boolean; email_address_value : (null | string); - groups_mode : int; + groups_changeable : boolean; groups_value : Array; } = await _espe.backend.invite_examine(key); @@ -64,23 +62,11 @@ lib_plankton.zoo_page.register( }), new lib_plankton.zoo_input.class_input_group( [ - { - "name": "name_value", - "input": new lib_plankton.zoo_input.class_input_text( - { - "read_only": (data.name_mode <= 1), - } - ), - /** - * @todo translate - */ - "label": "Name", - }, { "name": "membership_number_value", "input": new lib_plankton.zoo_input.class_input_text( { - "read_only": (data.membership_number_mode <= 1), + "read_only": (! data.membership_number_changeable), } ), /** @@ -88,27 +74,16 @@ lib_plankton.zoo_page.register( */ "label": "Mitgliedsnummer", }, - { - "name": "email_address_value", - "input": new lib_plankton.zoo_input.class_input_text( - { - "read_only": (data.email_address_mode <= 1), - } - ), - /** - * @todo translate - */ - "label": "E-Mail-Adresse", - }, { "name": "groups_value", "input": new lib_plankton.zoo_input.class_input_list( - () => new lib_plankton.zoo_input.class_input_text(), + () => new lib_plankton.zoo_input.class_input_text( + { + "read_only": (! data.groups_changeable), + } + ), { - /** - * @todo does not work yet - */ - // "read_only": (data.groups_mode <= 1), + "read_only": (! data.groups_changeable), } ), /** @@ -116,6 +91,30 @@ lib_plankton.zoo_page.register( */ "label": "Gruppen", }, + { + "name": "name_value", + "input": new lib_plankton.zoo_input.class_input_text( + { + "read_only": (! data.name_changeable), + } + ), + /** + * @todo translate + */ + "label": "Name", + }, + { + "name": "email_address_value", + "input": new lib_plankton.zoo_input.class_input_text( + { + "read_only": (! data.email_address_changeable), + } + ), + /** + * @todo translate + */ + "label": "E-Mail-Adresse", + }, ] ), [ diff --git a/source/pages/invite_list/logic.ts b/source/pages/invite_list/logic.ts new file mode 100644 index 0000000..54772b9 --- /dev/null +++ b/source/pages/invite_list/logic.ts @@ -0,0 +1,81 @@ +/* +Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend +Copyright (C) 2024 Christian Fraß + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later +version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see +. + */ + +lib_plankton.zoo_page.register( + "invite_list", + async (parameters, target_element) => { + type type_item = { + id : int; + key : string; + expiry : (null | int); + name_value : string; + }; + + target_element.appendChild(template_request("invite_list")); + + target_element.querySelector(".invite_list-title").textContent = lib_plankton.translate.get("page.invite_list.title"); + + const search : lib_plankton.zoo_search.type_search = lib_plankton.zoo_search.make( + (term) => _espe.backend.invite_list(), + { + "encode_item": (item) => lib_plankton.string.coin( + "[{{id}}] {{name}}: {{key}}", + { + "id": item.id.toFixed(0), + "name": item.name_value, + "key": item.key, + } + ), + "hooks_begin": [ + (term) => { + /** + * @todo + */ + } + ], + "hooks_select": [ + (item) => { + const url : URL = new URL(window.location.toString()); + url.hash = lib_plankton.string.coin( + "#invite_handle,key={{key}}", + { + "key": item.key, + } + ); + console.info(url.toString()); + } + ] + } + ); + lib_plankton.zoo_search.render( + search, + target_element.querySelector(".invite_list-search"), + { + "state": { + "term": "", + } + } + ); + + /* + const data = await _espe.backend.invite_list(); + (target_element.querySelector(".invite_list-data") as HTMLElement).textContent = JSON.stringify( + data, + undefined, + " " + ); + */ + } +); diff --git a/source/pages/invite_handle/style.css b/source/pages/invite_list/structure.html similarity index 80% rename from source/pages/invite_handle/style.css rename to source/pages/invite_list/structure.html index 791713b..c003993 100644 --- a/source/pages/invite_handle/style.css +++ b/source/pages/invite_list/structure.html @@ -1,4 +1,4 @@ -/* + + diff --git a/source/pages/list/logic.ts b/source/pages/list/logic.ts index 5377a8c..cbaab56 100644 --- a/source/pages/list/logic.ts +++ b/source/pages/list/logic.ts @@ -25,7 +25,7 @@ lib_plankton.zoo_page.register( }; }; const term : (null | string) = (parameters["term"] ?? ""); - + target_element.appendChild(template_request("list")); target_element.querySelector(".list-title").textContent = lib_plankton.translate.get("page.list.title"); diff --git a/source/pages/view/style.css b/source/pages/view/style.css index 87593c5..3094704 100644 --- a/source/pages/view/style.css +++ b/source/pages/view/style.css @@ -39,18 +39,3 @@ You should have received a copy of the GNU General Public License along with thi } */ -.plankton_form_actions > * -{ - display: block; - margin: 8px; -} - -section.view .plankton_input_list_element > * -{ - display: inline-block; -} - -section.view .plankton_input_list_element_input -{ - -} diff --git a/source/style/style.css b/source/style/style.css index 716df36..93e0517 100644 --- a/source/style/style.css +++ b/source/style/style.css @@ -30,7 +30,6 @@ html color: hsl(var(--hue), 0%, 100%); } - body { max-width: 960px; @@ -171,6 +170,12 @@ nav > ul > li:hover::after font-weight: bold; } +.plankton_form_actions > * +{ + display: block; + margin: 8px; +} + .plankton_search_item { cursor: pointer; @@ -210,7 +215,6 @@ nav > ul > li:hover::after display: block; } - .plankton_input_enumeration > * { display: block; @@ -236,3 +240,14 @@ nav > ul > li:hover::after { margin-bottom: 8px; } + + +.plankton_input_list_element > * +{ + display: inline-block; +} + +.plankton_input_list_element_input +{ + +} diff --git a/tools/makefile b/tools/makefile index 9968b9b..be17f5f 100644 --- a/tools/makefile +++ b/tools/makefile @@ -47,6 +47,7 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/pages/register/logic.ts \ ${dir_source}/pages/password_change_init/logic.ts \ ${dir_source}/pages/password_change_exec/logic.ts \ + ${dir_source}/pages/invite_list/logic.ts \ ${dir_source}/pages/invite_handle/logic.ts \ ${dir_source}/logic/main.ts @ ${cmd_log} "logic | compile …" @@ -69,8 +70,7 @@ ${dir_build}/style.css: \ ${dir_source}/pages/view/style.css \ ${dir_source}/pages/register/style.css \ ${dir_source}/pages/password_change_init/style.css \ - ${dir_source}/pages/password_change_exec/style.css \ - ${dir_source}/pages/invite_handle/style.css + ${dir_source}/pages/password_change_exec/style.css @ ${cmd_log} "style …" @ ${cmd_mkdir} $(dir $@) @ ${cmd_cat} $^ > $@ @@ -86,6 +86,7 @@ ${dir_build}/index.html: \ ${dir_source}/pages/register/structure.html \ ${dir_source}/pages/password_change_init/structure.html \ ${dir_source}/pages/password_change_exec/structure.html \ + ${dir_source}/pages/invite_list/structure.html \ ${dir_source}/pages/invite_handle/structure.html @ ${cmd_log} "structure …" @ ${cmd_mkdir} $(dir $@) -- 2.39.5 From 1f91b8f9c8b1ddd188482aa2121b93c4a4f4b1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Wed, 2 Jul 2025 18:33:14 +0200 Subject: [PATCH 3/3] [task-193] --- source/data/localization/deu.loc.json | 103 ++++--- source/data/localization/eng.loc.json | 107 ++++--- source/logic/backend.ts | 68 +++++ source/logic/main.ts | 15 +- source/pages/invite_create/logic.ts | 263 +++++++++++++++++ .../{list => invite_create}/structure.html | 6 +- source/pages/invite_create/style.css | 31 ++ source/pages/invite_handle/logic.ts | 269 ++++++++++-------- source/pages/invite_handle/structure.html | 10 +- source/pages/invite_handle/style.css | 27 ++ source/pages/invite_list/logic.ts | 45 ++- source/pages/invite_list/structure.html | 6 +- source/pages/{list => invite_list}/style.css | 4 + source/pages/invite_view/logic.ts | 249 ++++++++++++++++ .../{create => invite_view}/structure.html | 6 +- .../pages/{register => invite_view}/style.css | 16 +- source/pages/login/logic.ts | 2 +- .../pages/{create => member_create}/logic.ts | 31 +- .../{view => member_create}/structure.html | 9 +- .../pages/{create => member_create}/style.css | 0 source/pages/{list => member_list}/logic.ts | 28 +- source/pages/member_list/structure.html | 22 ++ source/pages/member_list/style.css | 19 ++ .../{register => member_register}/logic.ts | 45 +-- .../structure.html | 18 +- source/pages/member_register/style.css | 27 ++ source/pages/{view => member_view}/logic.ts | 42 +-- source/pages/member_view/structure.html | 22 ++ source/pages/{view => member_view}/style.css | 8 +- source/style/style.css | 4 +- tools/makefile | 34 ++- 31 files changed, 1193 insertions(+), 343 deletions(-) create mode 100644 source/pages/invite_create/logic.ts rename source/pages/{list => invite_create}/structure.html (87%) create mode 100644 source/pages/invite_create/style.css create mode 100644 source/pages/invite_handle/style.css rename source/pages/{list => invite_list}/style.css (94%) create mode 100644 source/pages/invite_view/logic.ts rename source/pages/{create => invite_view}/structure.html (87%) rename source/pages/{register => invite_view}/style.css (62%) rename source/pages/{create => member_create}/logic.ts (75%) rename source/pages/{view => member_create}/structure.html (85%) rename source/pages/{create => member_create}/style.css (100%) rename source/pages/{list => member_list}/logic.ts (75%) create mode 100644 source/pages/member_list/structure.html create mode 100644 source/pages/member_list/style.css rename source/pages/{register => member_register}/logic.ts (71%) rename source/pages/{register => member_register}/structure.html (68%) create mode 100644 source/pages/member_register/style.css rename source/pages/{view => member_view}/logic.ts (76%) create mode 100644 source/pages/member_view/structure.html rename source/pages/{view => member_view}/style.css (83%) diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 4e05eb9..2ea4083 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -4,52 +4,62 @@ }, "tree": { "common.not_used": "nicht verwendet", + "common.changeable": "änderbar", + "common.initial_value": "Vorausfüllung", + "common.timezone_shift": "Zeitzonen-Verschiebung", + "common.date": "Datum", + "common.time": "Uhzeit", + "domain.member.member": "Mitglied", + "domain.member.membership_number.label": "Mitgliedsnummer", + "domain.member.name_real_value.label": "Echter Name", + "domain.member.name_real_index.label": "Namens-Index", + "domain.member.groups.label": "Gruppen", + "domain.member.registered.label": "registriert", + "domain.member.enabled.label": "aktiviert", + "domain.member.email_address_private.label": "private E-Mail-Adresse", + "domain.member.email_address_veiled.label": "pseudonymisierte E-Mail-Adresse", + "domain.member.email_address_nominal.label": "namentliche E-Mail-Adresse", + "domain.member.email_redirect_to_private_address.label": "eingehende E-Mails zu privater Adresse umleiten", + "domain.member.email_allow_sending.label": "Versenden von E-Mails erlauben", + "domain.member.name_login.label": "Anmeldename", + "domain.member.password_set.label": "Passwort gesetzt", + "domain.invite.key.label": "Schlüssel", + "domain.invite.expiry.label": "Ablaufzeitpunkt", + "domain.invite.url.label": "URL", "page.login.title": "Anmelden", "page.login.name": "Name", "page.login.password": "Passwort", "page.login.submit": "Anmelden", - "page.create.title": "Mitglied anlegen", - "page.list.title": "Mitglieder-Liste", - "page.view.title": "Mitglied", - "page.view.form.field.membership_number.label": "Mitgliedsnummer", - "page.view.form.field.name_real_value.label": "Echter Name", - "page.view.form.field.name_real_index.label": "Namens-Index", - "page.view.form.field.groups.label": "Gruppen", - "page.view.form.field.registered.label": "registriert", - "page.view.form.field.enabled.label": "aktiviert", - "page.view.form.field.email_address_private.label": "private E-Mail-Adresse", - "page.view.form.field.email_address_veiled.label": "pseudonymisierte E-Mail-Adresse", - "page.view.form.field.email_address_nominal.label": "namentliche E-Mail-Adresse", - "page.view.form.field.email_redirect_to_private_address.label": "eingehende E-Mails zu privater Adresse umleiten", - "page.view.form.field.email_allow_sending.label": "Versenden von E-Mails erlauben", - "page.view.form.field.name_login.label": "Anmeldename", - "page.view.form.field.password_set.label": "Passwort gesetzt", - "page.view.form.action.save": "Änderungen speichern", - "page.view.form.action.summon": "Zur Registrierung auffordern", - "page.view.misc.summoned": "Benachrichtigung verschickt", - "page.view.misc.test_info": "Im Produktiv-Szenario würde an dieser Stelle eine E-Mail an die hinterlegte private E-Mail-Adresse des Mitglieds versendet werden mit einem Willkommens-Gruß und dem Aufruf folgenden Link zu öffnen:\n\n{{url}}", - "page.register.title": "Registrieren", - "page.register.form.field.email_address.label": "Partei-E-Mail-Adresse einrichten", - "page.register.form.field.email_address.help": "Für Partei-Angelegenheiten möchten wir dir anbieten gesonderte E-Mail-Adressen zu verwenden.\n\nDeine namentliche E-Mail-Adresse würde lauten »{{email_address_nominal}}« und die pseudonymisierte »{{email_address_veiled}}«\n\nDie Partei-E-Mail-Adressen können zum Empfangen von E-Mails verwendet werden. Falls es nötig werden sollte, dass du auch E-Mails mit über die Partei-Adresse verschicken kannst, wende dich bitte an den/die Mitgliederbeauftragte:n!", - "page.register.form.field.email_address.option.none": "keine", - "page.register.form.field.email_address.option.only_veiled": "nur pseudonymisiert", - "page.register.form.field.email_address.option.both": "pseudonymisiert und namentlich", - "page.register.form.field.email_redirect.label": "eingehende E-Mails an private Adresse leiten", - "page.register.form.field.email_redirect.help": "", - "page.register.form.field.password_value.label": "Passwort für Netz-Dienste", - "page.register.form.field.password_value.help": "das Passwort für die Anmeldung bei den Netz-Diensten.\n\nDu solltest dir merken oder geeignet abspeichern, was du hier einträgst.\n\nSolltest du dieses Passwort mal vergessen oder verlieren, hast du die Möglichkeit ein neues zu setzen.", - "page.register.form.field.password_confirmation.label": "Passwort wiederholen", - "page.register.form.field.password_confirmation.help": "", - "page.register.form.submit": "Abschicken", - "page.register.flaw.already_registered": "bereits registriert", - "page.register.flaw.password_mismatch": "die Passwörter stimmen nicht überein", - "page.register.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben", - "page.register.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben", - "page.register.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten", - "page.register.flaw.password_lacks_number": "das Passwort muss eine Zahl beinhalten", - "page.register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", - "page.register.flaw.unhandled_error": "da ist etwas schief gelaufen :/", - "page.register.success": "Danke!", + "page.logout.title": "Abmelden", + "page.member_create.title": "Mitglied anlegen", + "page.member_list.title": "Mitglieder", + "page.member_view.title": "Mitglied", + "page.member_view.form.action.save": "Änderungen speichern", + "page.member_view.form.action.summon": "Zur Registrierung auffordern", + "page.member_view.misc.summoned": "Benachrichtigung verschickt", + "page.member_view.misc.test_info": "Im Produktiv-Szenario würde an dieser Stelle eine E-Mail an die hinterlegte private E-Mail-Adresse des Mitglieds versendet werden mit einem Willkommens-Gruß und dem Aufruf folgenden Link zu öffnen:\n\n{{url}}", + "page.member_register.title": "Registrieren", + "page.member_register.form.field.email_address.label": "Partei-E-Mail-Adresse einrichten", + "page.member_register.form.field.email_address.help": "Für Partei-Angelegenheiten möchten wir dir anbieten gesonderte E-Mail-Adressen zu verwenden.\n\nDeine namentliche E-Mail-Adresse würde lauten »{{email_address_nominal}}« und die pseudonymisierte »{{email_address_veiled}}«\n\nDie Partei-E-Mail-Adressen können zum Empfangen von E-Mails verwendet werden. Falls es nötig werden sollte, dass du auch E-Mails mit über die Partei-Adresse verschicken kannst, wende dich bitte an den/die Mitgliederbeauftragte:n!", + "page.member_register.form.field.email_address.option.none": "keine", + "page.member_register.form.field.email_address.option.only_veiled": "nur pseudonymisiert", + "page.member_register.form.field.email_address.option.both": "pseudonymisiert und namentlich", + "page.member_register.form.field.email_redirect.label": "eingehende E-Mails an private Adresse leiten", + "page.member_register.form.field.email_redirect.help": "", + "page.member_register.form.field.password_value.label": "Passwort für Netz-Dienste", + "page.member_register.form.field.password_value.help": "das Passwort für die Anmeldung bei den Netz-Diensten.\n\nDu solltest dir merken oder geeignet abspeichern, was du hier einträgst.\n\nSolltest du dieses Passwort mal vergessen oder verlieren, hast du die Möglichkeit ein neues zu setzen.", + "page.member_register.form.field.password_confirmation.label": "Passwort wiederholen", + "page.member_register.form.field.password_confirmation.help": "", + "page.member_register.form.submit": "Abschicken", + "page.member_register.flaw.already_registered": "bereits registriert", + "page.member_register.flaw.password_mismatch": "die Passwörter stimmen nicht überein", + "page.member_register.flaw.password_too_short": "das Passwort muss mindestens {{minimum_length}} Zeichen haben", + "page.member_register.flaw.password_too_long": "das Passwort darf höchstens {{maximum_length}} Zeichen haben", + "page.member_register.flaw.password_lacks_letter": "das Passwort muss einen Buchstaben beinhalten", + "page.member_register.flaw.password_lacks_number": "das Passwort muss eine Zahl beinhalten", + "page.member_register.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", + "page.member_register.flaw.unhandled_error": "da ist etwas schief gelaufen :/", + "page.member_register.success": "Danke!", "page.password_change_init.title": "Passwort ändern", "page.password_change_init.info": "Falls dein Mitglieds-Konto zugeordnet werden kann, wird eine E-Mail mit weiteren Anweisungen an deine private Adresse geschickt.", "page.password_change_init.identifier": "Anmelde-Name oder private E-Mail-Adresse", @@ -71,6 +81,13 @@ "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", "page.password_change_exec.status.success": "erledigt", "page.invite_list.title": "Einladungen", - "page.invite_handle.title": "Einladung" + "page.invite_create.title": "Einladung anlegen", + "page.invite_create.form.field.send_immediatly.label": "Link sofort versenden", + "page.invite_create.form.action.submit": "anlegen", + "page.invite_view.title": "Einladung", + "page.invite_handle.title": "Einladung", + "page.invite_handle.message.invalid": "ungültig", + "page.invite_handle.message.successfull": "erfolgreich", + "page.invite_handle.form.action.submit": "annehmen" } } diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 333b68c..33217f8 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -4,52 +4,62 @@ }, "tree": { "common.not_used": "not used", - "page.login.title": "Login", + "common.changeable": "changeable", + "common.initial_value": "initial value", + "common.timezone_shift": "timezone shift", + "common.date": "date", + "common.time": "time", + "domain.member.member": "member", + "domain.member.membership_number.label": "membership number", + "domain.member.name_real_value.label": "real name", + "domain.member.name_real_index.label": "name index", + "domain.member.groups.label": "groups", + "domain.member.registered.label": "registered", + "domain.member.enabled.label": "enabled", + "domain.member.email_address_private.label": "private e-mail address", + "domain.member.email_address_veiled.label": "veiled e-mail address", + "domain.member.email_address_nominal.label": "nominal e-mail address", + "domain.member.email_redirect_to_private_address.label": "redirect incoming e-mails to private address", + "domain.member.email_allow_sending.label": "allow sending e-mails", + "domain.member.name_login.label": "login name", + "domain.member.password_set.label": "password set", + "domain.invite.key.label": "key", + "domain.invite.expiry.label": "expiration", + "domain.invite.url.url": "URL", + "page.login.title": "login", "page.login.name": "name", "page.login.password": "password", "page.login.submit": "login", - "page.create.title": "Create member", - "page.list.title": "Member list", - "page.view.title": "Member", - "page.view.form.field.membership_number.label": "membership number", - "page.view.form.field.name_real_value.label": "real name", - "page.view.form.field.name_real_index.label": "name index", - "page.view.form.field.groups.label": "groups", - "page.view.form.field.registered.label": "registered", - "page.view.form.field.enabled.label": "enabled", - "page.view.form.field.email_address_private.label": "private e-mail address", - "page.view.form.field.email_address_veiled.label": "veiled e-mail address", - "page.view.form.field.email_address_nominal.label": "nominal e-mail address", - "page.view.form.field.email_redirect_to_private_address.label": "redirect incoming e-mails to private address", - "page.view.form.field.email_allow_sending.label": "allow sending e-mails", - "page.view.form.field.name_login.label": "login name", - "page.view.form.field.password_set.label": "password set", - "page.view.form.action.save": "save changes", - "page.view.form.action.summon": "urge for registration", - "page.view.misc.summoned": "notification sent", - "page.view.misc.test_info": "in a productive environment the system would now send an e-mail to the member's private address with a welcome note and a call to open the following link:\n\n{{url}}", - "page.register.title": "Register", - "page.register.form.field.email_address.label": "Set up party e-mail address", - "page.register.form.field.email_address.help": "We offer you to use a special e-mail address for any party concerns.\n\nYour namely e-mail address would be »{{email_address_nominal}}« and the veiled one »{{email_address_veiled}}«\n\nThe party e-mail address may be used for the reception of e-mails. In case it becomes necessary for you to submit e-mails via a party address, please get in contact with your membership authority!", - "page.register.form.field.email_address.option.none": "none", - "page.register.form.field.email_address.option.only_veiled": "only veiled", - "page.register.form.field.email_address.option.both": "both, veiled and namely", - "page.register.form.field.email_redirect.label": "redirect incoming e-mails to private address", - "page.register.form.field.email_redirect.help": "", - "page.register.form.field.password_value.label": "password for online services", - "page.register.form.field.password_value.help": "the password for logging in to the online services\n\nYou should remember, denote or save properly, what you enter here.\n\nIn case you forget or lose the password some day, you can reset it.", - "page.register.form.field.password_confirmation.label": "confirm password", - "page.register.form.field.password_confirmation.help": "", - "page.register.form.submit": "submit", - "page.register.flaw.already_registered": "already registered", - "page.register.flaw.password_mismatch": "passwords do not match", - "page.register.flaw.password_too_short": "the password must have at least {{minimum_length}} characters", - "page.register.flaw.password_too_long": "the password must not have more than {{maximum_length}} characters", - "page.register.flaw.password_lacks_letter": "the password must contain a letter", - "page.register.flaw.password_lacks_number": "the password must contain a number", - "page.register.flaw.password_lacks_special_character": "the password must contain a special character", - "page.register.flaw.unhandled_error": "something went wrong :/", - "page.register.success": "Thanks!", + "page.logout.title": "logout", + "page.member_create.title": "Create member", + "page.member_list.title": "Members", + "page.member_view.title": "Member", + "page.member_view.form.action.save": "save changes", + "page.member_view.form.action.summon": "urge for registration", + "page.member_view.misc.summoned": "notification sent", + "page.member_view.misc.test_info": "in a productive environment the system would now send an e-mail to the member's private address with a welcome note and a call to open the following link:\n\n{{url}}", + "page.member_register.title": "Register", + "page.member_register.form.field.email_address.label": "Set up party e-mail address", + "page.member_register.form.field.email_address.help": "We offer you to use a special e-mail address for any party concerns.\n\nYour namely e-mail address would be »{{email_address_nominal}}« and the veiled one »{{email_address_veiled}}«\n\nThe party e-mail address may be used for the reception of e-mails. In case it becomes necessary for you to submit e-mails via a party address, please get in contact with your membership authority!", + "page.member_register.form.field.email_address.option.none": "none", + "page.member_register.form.field.email_address.option.only_veiled": "only veiled", + "page.member_register.form.field.email_address.option.both": "both, veiled and namely", + "page.member_register.form.field.email_redirect.label": "redirect incoming e-mails to private address", + "page.member_register.form.field.email_redirect.help": "", + "page.member_register.form.field.password_value.label": "password for online services", + "page.member_register.form.field.password_value.help": "the password for logging in to the online services\n\nYou should remember, denote or save properly, what you enter here.\n\nIn case you forget or lose the password some day, you can reset it.", + "page.member_register.form.field.password_confirmation.label": "confirm password", + "page.member_register.form.field.password_confirmation.help": "", + "page.member_register.form.submit": "submit", + "page.member_register.flaw.already_registered": "already registered", + "page.member_register.flaw.password_mismatch": "passwords do not match", + "page.member_register.flaw.password_too_short": "the password must have at least {{minimum_length}} characters", + "page.member_register.flaw.password_too_long": "the password must not have more than {{maximum_length}} characters", + "page.member_register.flaw.password_lacks_letter": "the password must contain a letter", + "page.member_register.flaw.password_lacks_number": "the password must contain a number", + "page.member_register.flaw.password_lacks_special_character": "the password must contain a special character", + "page.member_register.flaw.unhandled_error": "something went wrong :/", + "page.member_register.success": "Thanks!", "page.password_change_init.title": "Change Password", "page.password_change_init.info": "In case your member account can be found, an e-mail with further instructions will be sent to your private e-mail address.", "page.password_change_init.identifier": "Login name or private e-mail address", @@ -70,7 +80,14 @@ "page.password_change_exec.flaw.password_lacks_special_character": "das Passwort muss ein Sonderzeichen beinhalten", "page.password_change_exec.flaw.unhandled_error": "da ist etwas schief gelaufen :/", "page.password_change_exec.status.success": "done", - "page.invite_list.title": "Invites", - "page.invite_handle.title": "Invite" + "page.invite_list.title": "invites", + "page.invite_create.title": "create invite", + "page.invite_create.form.field.send_immediatly.label": "send link immediatly", + "page.invite_create.form.action.submit": "create", + "page.invite_view.title": "invitation", + "page.invite_handle.title": "invitation", + "page.invite_handle.message.invalid": "invalid", + "page.invite_handle.message.successfull": "successful", + "page.invite_handle.form.action.submit": "accept" } } diff --git a/source/logic/backend.ts b/source/logic/backend.ts index e9ca607..3e0417c 100644 --- a/source/logic/backend.ts +++ b/source/logic/backend.ts @@ -511,6 +511,74 @@ namespace _espe.backend } + /** + */ + export async function invite_read( + id : int + ) : Promise< + { + key : string; + expiry : (null | int); + membership_number_changeable : boolean; + membership_number_value : (null | string); + name_changeable : boolean; + name_value : string; + email_address_changeable : boolean; + email_address_value : (null | string); + groups_changeable : boolean; + groups_value : Array; + } + > + { + return abstract_call( + "GET", + lib_plankton.string.coin( + "/invite/read?id={{id}}", + { + "id": id.toFixed(0), + } + ) + ); + } + + + /** + */ + export async function invite_create( + data : { + membership_number_changeable : boolean; + membership_number_value : (null | string); + name_changeable : boolean; + name_value : string; + email_address_changeable : boolean; + email_address_value : (null | string); + groups_changeable : boolean; + groups_value : Array; + expiry : (null | int); + }, + send_immediatly : boolean, + notification_target_url_template : (null | string) + ) : Promise< + { + id : int; + key : string; + } + > + { + return abstract_call( + "POST", + "/invite/create", + { + "data": { + "data": data, + "notification_target_url_template": notification_target_url_template, + "send_immediatly": send_immediatly, + } + } + ); + } + + /** */ export async function invite_examine( diff --git a/source/logic/main.ts b/source/logic/main.ts index b53ada6..94e0fee 100644 --- a/source/logic/main.ts +++ b/source/logic/main.ts @@ -56,27 +56,22 @@ function setup_nav( > = [ { "location": {"name": "login", "parameters": {}}, - "label": "Anmelden", + "label": lib_plankton.translate.get("page.login.title"), "classes": ["logged_out"], }, { - "location": {"name": "list", "parameters": {}}, - "label": "Liste", - "classes": ["logged_in"], - }, - { - "location": {"name": "create", "parameters": {}}, - "label": "Anlegen", + "location": {"name": "member_list", "parameters": {}}, + "label": lib_plankton.translate.get("page.member_list.title"), "classes": ["logged_in"], }, { "location": {"name": "invite_list", "parameters": {}}, - "label": "Einladungen", + "label": lib_plankton.translate.get("page.invite_list.title"), "classes": ["logged_in"], }, { "location": {"name": "logout", "parameters": {}}, - "label": "Abmelden", + "label": lib_plankton.translate.get("page.logout.title"), "classes": ["logged_in"], }, ]; diff --git a/source/pages/invite_create/logic.ts b/source/pages/invite_create/logic.ts new file mode 100644 index 0000000..c551656 --- /dev/null +++ b/source/pages/invite_create/logic.ts @@ -0,0 +1,263 @@ +/* +Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Frontend +Copyright (C) 2024 Christian Fraß + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public +License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later +version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see +. + */ + +lib_plankton.zoo_page.register( + "invite_create", + async (parameters, target_element) => { + target_element.appendChild(template_request("invite_create")); + + target_element.querySelector(".invite_create-title").textContent = lib_plankton.translate.get("page.invite_create.title"); + + const indent = str => (/*"... " + */str); + + /** + * @todo outsource + */ + const null_when_empty = (str) => (((str === null) || (str === "")) ? null : str); + + const form = new lib_plankton.zoo_form.class_form< + { + data : { + membership_number_changeable : boolean; + membership_number_value : (null | string); + name_changeable : boolean; + name_value : string; + email_address_changeable : boolean; + email_address_value : (null | string); + groups_changeable : boolean; + groups_value : Array; + expiry : (null | int); + }; + send_immediatly : boolean; + }, + { + membership_number : { + changeable : boolean; + value : string; + }; + name : { + changeable : boolean; + value : string; + }; + email_address : { + changeable : boolean; + value : string; + }; + groups : { + changeable : boolean; + value : Array; + }; + expiry : (null | lib_plankton.pit.type_datetime); + send_immediatly : boolean; + } + >( + value => ({ + "membership_number": { + "changeable": value.data.membership_number_changeable, + "value": (value.data.membership_number_value ?? ""), + }, + "name": { + "changeable": value.data.name_changeable, + "value": value.data.name_value, + }, + "email_address": { + "changeable": value.data.email_address_changeable, + "value": (value.data.email_address_value ?? ""), + }, + "groups": { + "changeable": value.data.groups_changeable, + "value": value.data.groups_value, + }, + "expiry": ( + (value.data.expiry === null) + ? + null + : + lib_plankton.pit.to_datetime(lib_plankton.pit.from_unix_timestamp(value.data.expiry)) + ), + "send_immediatly": value.send_immediatly, + }), + representation => ({ + "data": { + "membership_number_changeable": representation.membership_number.changeable, + "membership_number_value": null_when_empty(representation.membership_number.value), + "name_changeable": representation.name.changeable, + "name_value": representation.name.value, + "email_address_changeable": representation.email_address.changeable, + "email_address_value": null_when_empty(representation.email_address.value), + "groups_changeable": representation.groups.changeable, + "groups_value": representation.groups.value, + "expiry": ( + (representation.expiry === null) + ? + null + : + lib_plankton.pit.to_unix_timestamp(lib_plankton.pit.from_datetime(representation.expiry)) + ), + }, + "send_immediatly": representation.send_immediatly, + }), + new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "membership_number", + "input": new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "value", + "input": new lib_plankton.zoo_input.class_input_text(), + "label": indent(lib_plankton.translate.get("common.initial_value")), + }, + { + "name": "changeable", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": indent(lib_plankton.translate.get("common.changeable")), + }, + ] + ), + "label": lib_plankton.translate.get("domain.member.membership_number.label"), + }, + { + "name": "groups", + "input": new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "value", + "input": new lib_plankton.zoo_input.class_input_list( + () => new lib_plankton.zoo_input.class_input_text() + ), + "label": indent(lib_plankton.translate.get("common.initial_value")), + }, + { + "name": "changeable", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": indent(lib_plankton.translate.get("common.changeable")), + }, + ] + ), + "label": lib_plankton.translate.get("domain.member.groups.label"), + }, + { + "name": "name", + "input": new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "value", + "input": new lib_plankton.zoo_input.class_input_text(), + "label": indent(lib_plankton.translate.get("common.initial_value")), + }, + { + "name": "changeable", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": indent(lib_plankton.translate.get("common.changeable")), + }, + ] + ), + "label": lib_plankton.translate.get("domain.member.name_real_value.label"), + }, + { + "name": "email_address", + "input": new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "value", + "input": new lib_plankton.zoo_input.class_input_text(), + "label": indent(lib_plankton.translate.get("common.initial_value")), + }, + { + "name": "changeable", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": indent(lib_plankton.translate.get("common.changeable")), + }, + ] + ), + "label": lib_plankton.translate.get("domain.member.email_address_private.label"), + }, + { + "name": "expiry", + "input": new lib_plankton.zoo_input.class_input_soft( + new lib_plankton.zoo_input.class_input_datetime_central_europe( + { + // "label_timezone_shift": indent(lib_plankton.translate.get("common.timezone_shift")), + "label_date": indent(lib_plankton.translate.get("common.date")), + "label_time": indent(lib_plankton.translate.get("common.time")), + } + ) + ), + "label": lib_plankton.translate.get("domain.invite.expiry.label"), + }, + { + "name": "send_immediatly", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": indent(lib_plankton.translate.get("page.invite_create.form.field.send_immediatly.label")), + }, + ] + ), + [ + { + "label": lib_plankton.translate.get("page.invite_create.form.action.submit"), + "procedure": async (get_value, get_representation) => { + const value = await get_value(); + const result : {id : int; key : string;} = await _espe.backend.invite_create( + value.data, + value.send_immediatly, + lib_plankton.zoo_page.encode( + { + "name": "invite_handle", + "parameters": { + "key": "{{key}}", + } + } + ) + ); + lib_plankton.zoo_page.set( + true + ? + { + "name": "invite_view", + "parameters": {"id": result.id.toFixed(0)} + } + : + { + "name": "invite_list", + "parameters": {} + } + ); + }, + } + ] + ); + await form.setup(target_element.querySelector(".invite_create-form") as HTMLElement); + form.input_write( + { + "data": { + "membership_number_changeable": false, + "membership_number_value": null, + "name_changeable": false, + "name_value": "", + "email_address_changeable": true, + "email_address_value": null, + "groups_changeable": false, + "groups_value": [], + /** + * @todo conf + */ + "expiry": lib_plankton.pit.shift_week(lib_plankton.pit.now(), 2), + }, + "send_immediatly": true, + } + ); + } +); diff --git a/source/pages/list/structure.html b/source/pages/invite_create/structure.html similarity index 87% rename from source/pages/list/structure.html rename to source/pages/invite_create/structure.html index 674709e..8961bd7 100644 --- a/source/pages/list/structure.html +++ b/source/pages/invite_create/structure.html @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with thi . --> -