diff --git a/lib/plankton/plankton.d.ts b/lib/plankton/plankton.d.ts index 8414b5a..c747db1 100644 --- a/lib/plankton/plankton.d.ts +++ b/lib/plankton/plankton.d.ts @@ -1,11 +1,11 @@ /** * @author fenris */ -declare type int = number; +type int = number; /** * @author fenris */ -declare type float = number; +type float = number; declare class Buffer { constructor(x: string, modifier?: string); toString(modifier?: string): string; @@ -19,7 +19,7 @@ declare namespace lib_plankton.base { /** * @author fenris */ -declare type type_pseudopointer = { +type type_pseudopointer = { value: type_value; }; /** @@ -1444,8 +1444,8 @@ declare namespace lib_plankton.list { /** * retrieves the element and its index of the list, which has the maximum value */ - function max(list: Array, target_function: ((element: type_element) => type_value), options: { - compare_value: ((value1: type_value, value2: type_value) => boolean); + function max(list: Array, target_function: ((element: type_element) => type_value), { "compare_value": compare_value, }?: { + compare_value?: ((value1: type_value, value2: type_value) => boolean); }): type_result_max; /** * retrieves the element and its index of the list, which has the mininum value @@ -2002,7 +2002,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; @@ -3793,6 +3793,9 @@ declare namespace lib_plankton.pit { /** */ function to_date_object(pit: type_pit): Date; + /** + */ + function from_date_object(date_object: Date): type_pit; /** * @todo test */ @@ -3814,6 +3817,12 @@ declare namespace lib_plankton.pit { /** */ function is_between(pit: type_pit, reference_left: type_pit, reference_right: type_pit): boolean; + /** + */ + function shift_second(pit: type_pit, increment: int): type_pit; + /** + */ + function shift_minute(pit: type_pit, increment: int): type_pit; /** */ function shift_hour(pit: type_pit, increment: int): type_pit; @@ -3895,14 +3904,15 @@ declare namespace lib_plankton.pit { function timezone_shift_format(timezone_shift: int): string; /** */ - function date_format(date: type_date): string; + function date_format(date: type_date, { "short": short, }?: { + short?: boolean; + }): 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; @@ -3912,11 +3922,15 @@ declare namespace lib_plankton.pit { }): 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, }?: { + function timespan_format(from: (null | type_datetime), to: (null | type_datetime), { "timezone_indicator": timezone_indicator, "show_timezone": show_timezone, "adjust_to_ce": adjust_to_ce, "omit_date": omit_date, "indicator_open_both": indicator_open_both, "indicator_open_right": indicator_open_right, "indicator_open_left": indicator_open_left, "indicator_closed": indicator_closed, }?: { timezone_indicator?: string; show_timezone?: boolean; adjust_to_ce?: boolean; omit_date?: boolean; + indicator_open_both?: string; + indicator_open_right?: string; + indicator_open_left?: string; + indicator_closed?: string; }): string; } declare namespace lib_plankton.translate { @@ -4509,8 +4523,9 @@ declare namespace lib_plankton.zoo_input { class class_input_text extends class_input_simple implements interface_input { /** */ - constructor({ "pattern": pattern, }?: { + constructor({ "pattern": pattern, "placeholder": placeholder, }?: { pattern?: (null | string); + placeholder?: (null | string); }); } } @@ -5148,6 +5163,56 @@ declare namespace lib_plankton.zoo_input { constructor(); } } +declare namespace lib_plankton.zoo_input { + /** + * @author fenris + */ + class class_input_file implements interface_input<(null | string | ArrayBuffer)> { + /** + */ + private required; + /** + */ + private mime_type; + /** + */ + private capture; + /** + */ + private dom_input; + /** + */ + constructor({ "required": required, "mime_type": mime_type, "capture": capture, }?: { + required?: boolean; + mime_type?: (null | string); + capture?: boolean; + }); + /** + * [implementation] + */ + setup(parent: HTMLElement): Promise; + /** + * [implementation] + */ + read(): Promise<(null | string | ArrayBuffer)>; + /** + * [implementation] + */ + write(value: (null | string | ArrayBuffer)): Promise; + /** + * [implementation] + */ + lock(mode: boolean): Promise; + /** + * [implementation] + */ + hook_change(action: (() => void)): Promise; + /** + * [implementation] + */ + focus(): void; + } +} declare namespace lib_plankton.zoo_form { /** */ diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index eb95740..0800bd3 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -2241,7 +2241,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -3849,10 +3849,8 @@ var lib_plankton; /** * retrieves the element and its index of the list, which has the maximum value */ - function max(list, target_function, options) { - options = Object.assign({ - "compare_value": instance_compare - }, options); + function max(list, target_function, _a) { + var _b = _a === void 0 ? {} : _a, _c = _b["compare_value"], compare_value = _c === void 0 ? (function (x, y) { return (x <= y); }) : _c; /*if (is_empty(list)) { throw (new Error("the max-arg of an empty list is not defined")); } @@ -3862,7 +3860,7 @@ var lib_plankton; var value = target_function(element); if ((result == null) || - (!options.compare_value(value, result.value))) { + (!compare_value(value, result.value))) { return { "index": index, "element": element, "value": value }; } else { @@ -9970,6 +9968,12 @@ var lib_plankton; * @author fenris */ class class_relation { + /** + * @author fenris + */ + check(value, reference) { + return this.predicate(value, reference); + } /** * @author fenris */ @@ -9979,12 +9983,6 @@ var lib_plankton; this.name = name; this.predicate = predicate; } - /** - * @author fenris - */ - check(value, reference) { - return this.predicate(value, reference); - } /** * @author fenris */ @@ -11390,6 +11388,7 @@ var lib_plankton; function from_date_object(date_object) { return Math.round(date_object.getTime() / 1000); } + pit_1.from_date_object = from_date_object; /** * @todo test */ @@ -11460,6 +11459,18 @@ var lib_plankton; is_before(pit, reference_right)); } pit_1.is_between = is_between; + /** + */ + function shift_second(pit, increment) { + return (pit + (increment)); + } + pit_1.shift_second = shift_second; + /** + */ + function shift_minute(pit, increment) { + return (pit + (60 * increment)); + } + pit_1.shift_minute = shift_minute; /** */ function shift_hour(pit, increment) { @@ -11783,8 +11794,9 @@ var lib_plankton; pit_1.timezone_shift_format = timezone_shift_format; /** */ - function date_format(date) { - return lib_plankton.string.coin("{{year}}-{{month}}-{{day}}", { + function date_format(date, { "short": short = false, } = {}) { + return lib_plankton.string.coin("{{year}}{{separator}}{{month}}{{separator}}{{day}}", { + "separator": (short ? "" : "-"), "year": date.year.toFixed(0).padStart(4, "0"), "month": date.month.toFixed(0).padStart(2, "0"), "day": date.day.toFixed(0).padStart(2, "0"), @@ -11806,7 +11818,6 @@ var lib_plankton; } 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) { @@ -11849,49 +11860,77 @@ var lib_plankton; 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 + function timespan_format(from, to, { "timezone_indicator": timezone_indicator = "", "show_timezone": show_timezone = false, "adjust_to_ce": adjust_to_ce = false, "omit_date": omit_date = false, "indicator_open_both": indicator_open_both = "?", "indicator_open_right": indicator_open_right = "> ", "indicator_open_left": indicator_open_left = "< ", "indicator_closed": indicator_closed = " — ", } = {}) { + const from_adjusted = ((from === null) ? - datetime_translate_ce(from) + null : - from); + (adjust_to_ce + ? + datetime_translate_ce(from) + : + from)); const to_adjusted = ((to === null) ? null : - (option_adjust_to_ce + (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), - }) - : - ""), - }); + return (((to_adjusted === null) + && + (from_adjusted === null)) + ? + indicator_open_both + : + lib_plankton.string.coin("{{prefix}}{{from_macro}}{{interfix}}{{to_macro}}{{macro_timezone}}", { + "prefix": ((to_adjusted === null) + ? + indicator_open_right + : + ""), + "from_macro": ((from_adjusted === null) + ? + "" + : + datetime_format(from_adjusted, { + "show_timezone": false, + "adjust_to_ce": false, + "omit_date": omit_date, + })), + "interfix": ((from_adjusted === null) + ? + indicator_open_left + : + ((to_adjusted === null) + ? + "" + : + indicator_closed)), + "to_macro": ((to_adjusted === null) + ? + "" + : + datetime_format(to_adjusted, { + "omit_date": ((from_adjusted !== null) + && + ((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": (show_timezone + ? + lib_plankton.string.coin(" [{{timezone_indicator}}{{timezone_value}}]", { + "timezone_indicator": timezone_indicator, + "timezone_value": timezone_shift_format(from_adjusted.timezone_shift), + }) + : + ""), + })); } pit_1.timespan_format = timespan_format; })(pit = lib_plankton.pit || (lib_plankton.pit = {})); @@ -13625,12 +13664,13 @@ var lib_plankton; class class_input_text extends zoo_input.class_input_simple { /** */ - constructor({ "pattern": pattern = null, + constructor({ "pattern": pattern = null, "placeholder": placeholder = null, // "autocompletion_list": autocompletion_list = null, } = {}) { super("text", representation => representation, value => value, { "additional_attributes": { "pattern": pattern, + "placeholder": placeholder, } }); } @@ -15305,6 +15345,138 @@ 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-2025 'kcf' + +»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_file { + /** + */ + constructor({ "required": required = false, "mime_type": mime_type = null, "capture": capture = false, } = {}) { + this.required = required; + this.mime_type = mime_type; + this.capture = capture; + this.dom_input = null; + } + /** + * [implementation] + */ + setup(parent) { + this.dom_input = document.createElement("input"); + this.dom_input.setAttribute("type", "file"); + if (this.mime_type === null) { + // do nothing + } + else { + this.dom_input.setAttribute("accept", this.mime_type); + } + if (!this.capture) { + // do nothing + } + else { + this.dom_input.setAttribute("capture", "capture"); + } + if (!this.required) { + // do nothing + } + else { + this.dom_input.setAttribute("required", "required"); + } + parent.appendChild(this.dom_input); + return Promise.resolve(undefined); + } + /** + * [implementation] + */ + read() { + if (this.required && (!this.dom_input.reportValidity())) { + return Promise.reject("required"); + } + else { + return (new Promise((resolve, reject) => { + if (this.dom_input.files.length <= 0) { + resolve(null); + } + else { + const file = this.dom_input.files[0]; + const reader = new FileReader(); + reader.onerror = () => { + reader.abort(); + reject(new Error()); + }; + reader.onload = (event) => { + resolve(reader.result); + }; + // reader.readAsDataURL(file); + reader.readAsArrayBuffer(file); + } + })); + } + } + /** + * [implementation] + */ + write(value) { + if (value === null) { + this.dom_input.value = null; + return Promise.resolve(undefined); + } + else { + return Promise.reject(new Error("not implemented (might even be impossible)")); + } + } + /** + * [implementation] + */ + lock(mode) { + if (mode) { + this.dom_input.setAttribute("disabled", "disabled"); + } + else { + this.dom_input.removeAttribute("disabled"); + } + return Promise.resolve(undefined); + } + /** + * [implementation] + */ + hook_change(action) { + this.dom_input.addEventListener("change", () => { + action(); + }); + return Promise.resolve(undefined); + } + /** + * [implementation] + */ + focus() { + this.dom_input.focus(); + } + } + zoo_input.class_input_file = class_input_file; + })(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-2025 'kcf' diff --git a/source/helpers.ts b/source/helpers.ts index 19d0360..491a5c1 100644 --- a/source/helpers.ts +++ b/source/helpers.ts @@ -304,25 +304,110 @@ namespace _dali.helpers /** */ export function datetime_input( + use_fallback : boolean ) : lib_plankton.zoo_input.interface_input { return ( - _dali.conf.get().misc.use_central_europe_specific_datetime_inputs + use_fallback ? - new lib_plankton.zoo_input.class_input_datetime_central_europe( + new lib_plankton.zoo_input.class_input_wrapped< { - "label_date": lib_plankton.translate.get("common.date"), - "label_time": lib_plankton.translate.get("common.time"), + date : string; + time : string; + }, + lib_plankton.pit.type_datetime + >( + new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "date", + "input": new lib_plankton.zoo_input.class_input_text( + { + "pattern": "[0-9]{4}-[0-9]{2}-[0-9]{2}", + "placeholder": "YYYY-MM-DD", + } + ), + "label": lib_plankton.translate.get("common.date"), + }, + { + "name": "time", + "input": new lib_plankton.zoo_input.class_input_text( + { + "pattern": "[0-9]{2}:[0-9]{2}", + "placeholder": "HH:MM", + } + ), + "label": lib_plankton.translate.get("common.time"), + }, + ] + ), + (inner) => { + const date_parts : Array = inner.date.split("-"); + const time_parts : Array = inner.time.split(":"); + const datetime_raw : lib_plankton.pit.type_datetime = { + "timezone_shift": 0, + "date": { + "year": parseInt(date_parts[0]), + "month": parseInt(date_parts[1]), + "day": parseInt(date_parts[2]), + }, + "time": { + "hour": parseInt(time_parts[0]), + "minute": parseInt(time_parts[1]), + "second": 0, + }, + }; + return { + "timezone_shift": ( + _dali.conf.get().misc.use_central_europe_specific_datetime_inputs + ? + lib_plankton.pit.timezone_shift_ce(lib_plankton.pit.from_datetime(datetime_raw)) + : + 0 + ), + "date": datetime_raw.date, + "time": datetime_raw.time, + }; + }, + (outer) => { + return { + "date": lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": outer.date.year.toFixed(0).padStart(4, "0"), + "month": outer.date.month.toFixed(0).padStart(2, "0"), + "day": outer.date.day.toFixed(0).padStart(2, "0"), + } + ), + "time": lib_plankton.string.coin( + "{{hour}}:{{minute}}", + { + "hour": outer.time.hour.toFixed(0).padStart(2, "0"), + "minute": outer.time.minute.toFixed(0).padStart(2, "0"), + } + ), + } } ) : - new lib_plankton.zoo_input.class_input_datetime( - { - "label_timezone_shift": lib_plankton.translate.get("common.timezone_shift"), - "label_date": lib_plankton.translate.get("common.date"), - "label_time": lib_plankton.translate.get("common.time"), - } + ( + _dali.conf.get().misc.use_central_europe_specific_datetime_inputs + ? + new lib_plankton.zoo_input.class_input_datetime_central_europe( + { + "label_date": lib_plankton.translate.get("common.date"), + "label_time": lib_plankton.translate.get("common.time"), + } + ) + : + new lib_plankton.zoo_input.class_input_datetime( + { + "label_timezone_shift": lib_plankton.translate.get("common.timezone_shift"), + "label_date": lib_plankton.translate.get("common.date"), + "label_time": lib_plankton.translate.get("common.time"), + } + ) ) ); } diff --git a/source/main.ts b/source/main.ts index 3de64e9..b54bbaa 100644 --- a/source/main.ts +++ b/source/main.ts @@ -198,11 +198,11 @@ namespace _dali ); if (status.logged_in) { - _dali.notify_login(status.name); + await _dali.notify_login(status.name); } else { - _dali.notify_logout(); + await _dali.notify_logout(); } } diff --git a/source/model.ts b/source/model.ts index 6c59456..9d1b06b 100644 --- a/source/model.ts +++ b/source/model.ts @@ -36,6 +36,10 @@ namespace _dali.model name : string; } >; + settings : { + use_fallback_for_date_and_time_inputs : boolean; + weekview_vertical_default : boolean; + }; calendars : ( null | @@ -170,6 +174,18 @@ namespace _dali.model } + /** + */ + export async function settings( + ) + : Promise< + _dali.type_user_settings + > + { + return Promise.resolve(_state.settings); + } + + /** */ async function sync_calendars( @@ -637,6 +653,10 @@ namespace _dali.model _state = { "groups": [], "users": [], + "settings": { + "use_fallback_for_date_and_time_inputs": false, + "weekview_vertical_default": false, + }, "calendars": lib_plankton.map.hashmap.implementation_map( lib_plankton.map.hashmap.make( calendar_id => calendar_id.toFixed(0) @@ -668,6 +688,7 @@ namespace _dali.model ) ); _state.users = await _dali.backend.user_list(); + _state.settings = (await _dali.backend.user_get()).settings; await sync_calendars(); lib_plankton.map.clear(_state.events); lib_plankton.set.clear(_state.covered_dates); diff --git a/source/resources/backend.ts b/source/resources/backend.ts index 43d7543..b39c7f3 100644 --- a/source/resources/backend.ts +++ b/source/resources/backend.ts @@ -421,6 +421,41 @@ namespace _dali.backend } + /** + */ + export function user_get( + ) + : Promise< + { + name : string; + groups : Array< + int + >; + email_address : ( + null + | + string + ); + dav_token : ( + null + | + string + ); + settings : { + use_fallback_for_date_and_time_inputs : boolean; + weekview_vertical_default : boolean; + }; + } + > + { + return call( + lib_plankton.http.enum_method.get, + "/user", + null + ); + } + + /** */ export function user_dav_conf( diff --git a/source/types.ts b/source/types.ts index 5767175..b1808e0 100644 --- a/source/types.ts +++ b/source/types.ts @@ -52,6 +52,14 @@ namespace _dali export type type_user_id = int; + /** + */ + export type type_user_settings = { + use_fallback_for_date_and_time_inputs : boolean; + weekview_vertical_default : boolean; + }; + + /** */ export type type_user_object = { @@ -62,6 +70,7 @@ namespace _dali | string ); + settings : type_user_settings; }; diff --git a/source/widgets/event_edit/logic.ts b/source/widgets/event_edit/logic.ts index 73fb7bc..edbe3ba 100644 --- a/source/widgets/event_edit/logic.ts +++ b/source/widgets/event_edit/logic.ts @@ -212,6 +212,7 @@ namespace _dali.widgets { "name": "event_begin", "input": _dali.helpers.datetime_input( + (await _dali.model.settings()).use_fallback_for_date_and_time_inputs ), "label": lib_plankton.translate.get("event.begin") }, @@ -219,6 +220,7 @@ namespace _dali.widgets "name": "event_end", "input": new lib_plankton.zoo_input.class_input_soft( _dali.helpers.datetime_input( + (await _dali.model.settings()).use_fallback_for_date_and_time_inputs ) ), "label": lib_plankton.translate.get("event.end") diff --git a/source/widgets/overview/logic.ts b/source/widgets/overview/logic.ts index a3ad008..23ee458 100644 --- a/source/widgets/overview/logic.ts +++ b/source/widgets/overview/logic.ts @@ -569,7 +569,11 @@ namespace _dali.widgets this.get_entries, { "initial_view_mode": view_mode, - "weekview_initial_vertical": (view_kind === _dali.enum_view_kind.touch), + "weekview_initial_vertical": ( + (await _dali.model.settings()).weekview_vertical_default + || + (view_kind === _dali.enum_view_kind.touch) + ), "action_create_event": this.action_create_event, "action_edit_event": this.action_edit_event, } diff --git a/tools/makefile b/tools/makefile index 8525d3f..598c6d7 100644 --- a/tools/makefile +++ b/tools/makefile @@ -2,7 +2,7 @@ dir_lib := lib dir_source := source -dir_temp := /tmp/zeitbild-frontend-web-temp +dir_temp := /tmp/dali-temp dir_build := build dir_tools := tools