Merge branch 'task-408'

This commit is contained in:
fenris 2025-10-17 00:56:05 +02:00
commit 1d4ee08b06
50 changed files with 4860 additions and 2836 deletions

View file

@ -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_value> = {
type type_pseudopointer<type_value> = {
value: type_value;
};
/**
@ -1969,7 +1969,7 @@ declare namespace lib_plankton.storage.memory {
clear(): Promise<void>;
write(key: any, value: any): Promise<boolean>;
delete(key: any): Promise<void>;
read(key: any): Promise<type_item>;
read(key: any): Promise<Awaited<type_item>>;
search(term: any): Promise<{
key: string;
preview: string;
@ -2693,6 +2693,173 @@ declare namespace lib_plankton.map.collatemap {
export function implementation_map<type_key, type_value>(subject: type_subject<type_key, type_value>): type_map<type_key, type_value>;
export {};
}
declare namespace lib_plankton.set {
/**
*/
type type_set<type_element> = {
size: (() => int);
has: ((element: type_element) => boolean);
add: ((element: type_element) => void);
remove: ((element: type_element) => void);
iterate: ((procedure: ((element: type_element) => void)) => void);
};
}
declare namespace lib_plankton.set {
/**
*/
function clear<type_element>(set: type_set<type_element>): void;
/**
*/
function dump<type_element>(set: type_set<type_element>): Array<type_element>;
/**
*/
function show<type_element>(set: type_set<type_element>, { "show_element": show_element, }?: {
show_element?: ((element: type_element) => string);
}): string;
/**
*/
function map<type_element_from, type_element_to>(construct: (() => type_set<type_element_to>), set: type_set<type_element_from>, transformator: ((element: type_element_from) => type_element_to)): type_set<type_element_to>;
/**
*/
function filter<type_element>(construct: (() => type_set<type_element>), set: type_set<type_element>, predicate: ((element: type_element) => boolean)): type_set<type_element>;
/**
*/
function subset<type_element>(set1: type_set<type_element>, set2: type_set<type_element>): boolean;
/**
*/
function superset<type_element>(set1: type_set<type_element>, set2: type_set<type_element>): boolean;
/**
*/
function equal<type_element>(set1: type_set<type_element>, set2: type_set<type_element>): boolean;
/**
*/
function empty<type_element>(set: type_set<type_element>): boolean;
/**
*/
function union<type_element>(construct: (() => type_set<type_element>), set1: type_set<type_element>, set2: type_set<type_element>): type_set<type_element>;
/**
*/
function intersection<type_element>(construct: (() => type_set<type_element>), set1: type_set<type_element>, set2: type_set<type_element>): type_set<type_element>;
/**
*/
function difference<type_element>(construct: (() => type_set<type_element>), set1: type_set<type_element>, set2: type_set<type_element>): type_set<type_element>;
/**
*/
function symmetric_difference<type_element>(construct: (() => type_set<type_element>), set1: type_set<type_element>, set2: type_set<type_element>): type_set<type_element>;
}
declare namespace lib_plankton.set.hashset {
/**
*/
type type_hashing<type_element> = ((element: type_element) => string);
/**
*/
export type type_subject<type_element> = {
core: lib_plankton.map.hashmap.type_subject<type_element, null>;
};
/**
*/
export function make<type_element>(hashing: type_hashing<type_element>, options?: {
elements?: Array<type_element>;
}): type_subject<type_element>;
/**
*/
export function size<type_element>(subject: type_subject<type_element>): int;
/**
*/
export function has<type_element>(subject: type_subject<type_element>, element: type_element): boolean;
/**
*/
export function add<type_element>(subject: type_subject<type_element>, element: type_element): void;
/**
*/
export function remove<type_element>(subject: type_subject<type_element>, element: type_element): void;
/**
*/
export function iterate<type_element>(subject: type_subject<type_element>, procedure: ((element: type_element) => void)): void;
/**
*/
export function implementation_set<type_element>(subject: type_subject<type_element>): type_set<type_element>;
export {};
}
declare namespace lib_plankton.set.collateset {
/**
*/
type type_collation<type_element> = ((x: type_element, y: type_element) => boolean);
/**
*/
export type type_subject<type_element> = {
core: lib_plankton.map.collatemap.type_subject<type_element, null>;
};
/**
*/
export function make<type_element>(collation: type_collation<type_element>, options?: {
elements?: Array<type_element>;
}): type_subject<type_element>;
/**
*/
export function size<type_element>(subject: type_subject<type_element>): int;
/**
*/
export function has<type_element>(subject: type_subject<type_element>, element: type_element): boolean;
/**
*/
export function add<type_element>(subject: type_subject<type_element>, element: type_element): void;
/**
*/
export function remove<type_element>(subject: type_subject<type_element>, element: type_element): void;
/**
*/
export function iterate<type_element>(subject: type_subject<type_element>, procedure: ((element: type_element) => void)): void;
/**
*/
export function implementation_set<type_element>(subject: type_subject<type_element>): type_set<type_element>;
export {};
}
declare namespace lib_plankton.cache {
/**
*/
type type_result<type_value> = {
retrieved: boolean;
value: type_value;
};
/**
*/
type type_entry<type_value> = {
value: type_value;
expiry: (null | float);
};
/**
*/
type type_subject<type_value> = lib_plankton.storage.type_chest<string, type_entry<type_value>, void, any, any>;
}
declare namespace lib_plankton.cache {
/**
*/
function make<type_value>({ "chest": chest, }?: {
chest?: lib_plankton.storage.type_chest<string, type_entry<type_value>, void, any, any>;
}): type_subject<type_value>;
/**
*/
function init<type_value>(subject: type_subject<type_value>): Promise<void>;
/**
*/
function clear<type_value>(subject: type_subject<type_value>): Promise<void>;
/**
*/
function invalidate<type_value>(subject: type_subject<type_value>, key: string): Promise<void>;
/**
*/
function query<type_value>(subject: type_subject<type_value>, key: string, lifetime: (null | float), retrieve: (() => Promise<type_value>)): Promise<type_result<type_value>>;
/**
* syntactic sugar: if the information, whether the value was retrieved, is irrelevant
*/
function get<type_value>(subject: type_subject<type_value>, key: string, lifetime: (null | float), retrieve: (() => Promise<type_value>)): Promise<type_value>;
/**
*/
function get_complex<type_input, type_value>(cache: type_subject<type_value>, group: string, input: type_input, lifetime: (null | float), retrieve: ((input: type_input) => Promise<type_value>), { "encode_input": encode_input, }?: {
encode_input?: ((input: type_input) => string);
}): Promise<type_value>;
}
declare namespace lib_plankton.complex {
/**
* @author fenris
@ -3809,55 +3976,6 @@ declare namespace lib_plankton.translate {
*/
function stance(str: string): string;
}
declare namespace lib_plankton.zoo_page {
/**
*/
export type type_location = {
name: string;
parameters: Record<string, any>;
};
/**
*/
type type_handler = ((parameters: Record<string, any>, target_element: Element) => void);
/**
*/
type type_nav_entry_definition = {
location: type_location;
label: string;
groups: Array<string>;
};
/**
*/
export let _pool: Record<string, type_handler>;
/**
*/
export function encode(location: type_location): string;
/**
* encodes a location in the URL and loads it
*/
export function set(location: type_location): void;
/**
*/
export function reload(): Promise<void>;
/**
*/
export function register(location_name: string, handler: type_handler): void;
/**
*/
export function nav_set_groups(groups: (null | Array<string>)): void;
/**
*/
export function init(target_element: Element, { "pool": pool, "fallback": fallback, "nav_entries": nav_entries, "nav_initial_groups": nav_initial_groups, }?: {
pool?: Record<string, type_handler>;
fallback?: (null | type_location);
nav_entries?: Array<type_nav_entry_definition>;
nav_initial_groups?: (null | Array<string>);
}): void;
/**
*/
export function start(): void;
export {};
}
declare namespace lib_plankton.zoo_widget {
/**
*/
@ -4043,6 +4161,55 @@ declare namespace lib_plankton.zoo_widget {
load(target_element: HTMLElement): Promise<void>;
}
}
declare namespace lib_plankton.zoo_page {
/**
*/
export type type_location = {
name: string;
parameters: Record<string, any>;
};
/**
*/
type type_handler = ((parameters: Record<string, any>, target_element: Element) => void);
/**
*/
type type_nav_entry_definition = {
location: type_location;
label: string;
groups: Array<string>;
};
/**
*/
export let _pool: Record<string, type_handler>;
/**
*/
export function encode(location: type_location): string;
/**
* encodes a location in the URL and loads it
*/
export function set(location: type_location): void;
/**
*/
export function reload(): Promise<void>;
/**
*/
export function register(location_name: string, handler: type_handler): void;
/**
*/
export function nav_set_groups(groups: (null | Array<string>)): void;
/**
*/
export function init(target_element: Element, { "pool": pool, "fallback": fallback, "nav_entries": nav_entries, "nav_initial_groups": nav_initial_groups, }?: {
pool?: Record<string, type_handler>;
fallback?: (null | type_location);
nav_entries?: Array<type_nav_entry_definition>;
nav_initial_groups?: (null | Array<string>);
}): void;
/**
*/
export function start(): void;
export {};
}
declare namespace lib_plankton.zoo_input {
/**
* @author fenris

View file

@ -2151,7 +2151,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
@ -8570,7 +8570,7 @@ the Free Software Foundation, either version 3 of the License, or
»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.
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 <http://www.gnu.org/licenses/>.
@ -8710,6 +8710,498 @@ var lib_plankton;
})(map = lib_plankton.map || (lib_plankton.map = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:set«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:set« 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:set« 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:set«. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file is part of »bacterio-plankton:set«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:set« 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:set« 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:set«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var set;
(function (set_1) {
/**
*/
function clear(set) {
set.iterate(function (element) {
set.remove(element);
});
}
set_1.clear = clear;
/**
*/
function dump(set) {
var elements = [];
set.iterate(function (element) {
elements.push(element);
});
return elements;
}
set_1.dump = dump;
/**
*/
function show(set, _a) {
var _b = _a === void 0 ? {} : _a, _c = _b["show_element"], show_element = _c === void 0 ? instance_show : _c;
return ("{"
+
(dump(set)
.map(function (element) { return (show_element(element)); })
.join(", "))
+
"}");
}
set_1.show = show;
/**
*/
function map(construct, set, transformator) {
var result = construct();
set.iterate(function (element_from) {
var element_to = transformator(element_from);
result.add(element_to);
});
return result;
}
set_1.map = map;
/**
*/
function filter(construct, set, predicate) {
var result = construct();
set.iterate(function (element) {
if (!predicate(element)) {
// do nothing
}
else {
result.add(element);
}
});
return result;
}
set_1.filter = filter;
/**
*/
function subset(set1, set2) {
var result;
set1.iterate(function (element) {
if (!set2.has(element)) {
result = false;
}
else {
// do nothing
}
});
return result;
}
set_1.subset = subset;
/**
*/
function superset(set1, set2) {
return subset(set2, set1);
}
set_1.superset = superset;
/**
*/
function equal(set1, set2) {
return (subset(set1, set2)
&&
superset(set1, set2));
}
set_1.equal = equal;
/**
*/
function empty(set) {
return (set.size() <= 0);
}
set_1.empty = empty;
/**
*/
function union(construct, set1, set2) {
var result = construct();
set1.iterate(function (element) {
result.add(element);
});
set2.iterate(function (element) {
result.add(element);
});
return result;
}
set_1.union = union;
/**
*/
function intersection(construct, set1, set2) {
var result = construct();
set1.iterate(function (element) {
if (!set2.has(element)) {
// do nothing
}
else {
result.add(element);
}
});
return result;
}
set_1.intersection = intersection;
/**
*/
function difference(construct, set1, set2) {
var result = construct();
set1.iterate(function (element) {
if (set2.has(element)) {
// do nothing
}
else {
result.add(element);
}
});
return result;
}
set_1.difference = difference;
/**
*/
function symmetric_difference(construct, set1, set2) {
// X $ Y = (X Y) \ (X ∩ Y)
return (difference(construct, union(construct, set1, set2), intersection(construct, set1, set2)));
}
set_1.symmetric_difference = symmetric_difference;
})(set = lib_plankton.set || (lib_plankton.set = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:set«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:set« 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:set« 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:set«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var set;
(function (set) {
var hashset;
(function (hashset) {
/**
*/
function make(hashing, options) {
if (options === void 0) { options = {}; }
options = Object.assign({
"elements": []
}, options);
return {
"core": lib_plankton.map.hashmap.make(hashing, {
"pairs": (options.elements
.map(function (element) { return ({
"key": element,
"value": null
}); }))
})
};
}
hashset.make = make;
/**
*/
function size(subject) {
return lib_plankton.map.hashmap.size(subject.core);
}
hashset.size = size;
/**
*/
function has(subject, element) {
return lib_plankton.map.hashmap.has(subject.core, element);
}
hashset.has = has;
/**
*/
function add(subject, element) {
return lib_plankton.map.hashmap.set(subject.core, element, null);
}
hashset.add = add;
/**
*/
function remove(subject, element) {
lib_plankton.map.hashmap.delete_(subject.core, element);
}
hashset.remove = remove;
/**
*/
function iterate(subject, procedure) {
lib_plankton.map.hashmap.iterate(subject.core, function (value, key) { procedure(key); });
}
hashset.iterate = iterate;
/**
*/
function implementation_set(subject) {
return {
"size": function () { return size(subject); },
"has": function (element) { return has(subject, element); },
"add": function (element) { return add(subject, element); },
"remove": function (element) { return remove(subject, element); },
"iterate": function (procedure) { return iterate(subject, procedure); }
};
}
hashset.implementation_set = implementation_set;
})(hashset = set.hashset || (set.hashset = {}));
})(set = lib_plankton.set || (lib_plankton.set = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:set«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:set« 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:set« 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:set«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var set;
(function (set) {
var collateset;
(function (collateset) {
/**
*/
function make(collation, options) {
if (options === void 0) { options = {}; }
options = Object.assign({
"elements": []
}, options);
return {
"core": lib_plankton.map.collatemap.make(collation, {
"pairs": (options.elements
.map(function (element) { return ({
"key": element,
"value": null
}); }))
})
};
}
collateset.make = make;
/**
*/
function size(subject) {
return lib_plankton.map.collatemap.size(subject.core);
}
collateset.size = size;
/**
*/
function has(subject, element) {
return lib_plankton.map.collatemap.has(subject.core, element);
}
collateset.has = has;
/**
*/
function add(subject, element) {
return lib_plankton.map.collatemap.set(subject.core, element, null);
}
collateset.add = add;
/**
*/
function remove(subject, element) {
lib_plankton.map.collatemap.delete_(subject.core, element);
}
collateset.remove = remove;
/**
*/
function iterate(subject, procedure) {
lib_plankton.map.collatemap.iterate(subject.core, function (key, value) { procedure(key); });
}
collateset.iterate = iterate;
/**
*/
function implementation_set(subject) {
return {
"size": function () { return size(subject); },
"has": function (element) { return has(subject, element); },
"add": function (element) { return add(subject, element); },
"remove": function (element) { return remove(subject, element); },
"iterate": function (procedure) { return iterate(subject, procedure); }
};
}
collateset.implementation_set = implementation_set;
})(collateset = set.collateset || (set.collateset = {}));
})(set = lib_plankton.set || (lib_plankton.set = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:cache«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:cache« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»bacterio-plankton:cache« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:cache«. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file is part of »bacterio-plankton:cache«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:cache« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»bacterio-plankton:cache« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:cache«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var cache;
(function (cache_1) {
/**
*/
function make({ "chest": chest = lib_plankton.storage.memory.implementation_chest({}), } = {}) {
return chest;
}
cache_1.make = make;
/**
*/
function init(subject) {
return subject.setup(undefined);
}
cache_1.init = init;
/**
*/
function clear(subject) {
return subject.clear();
}
cache_1.clear = clear;
/**
*/
function invalidate(subject, key) {
return subject.delete(key);
}
cache_1.invalidate = invalidate;
/**
*/
async function query(subject, key, lifetime, retrieve) {
const now = lib_plankton.base.get_current_timestamp();
return ((subject.read(key)
.then((entry) => Promise.resolve({
"found": true,
"entry": entry,
}))
.catch(() => Promise.resolve({
"found": false,
"entry": null,
})))
.then((item) => {
if ((!item.found)
||
((item.entry.expiry !== null)
&&
(item.entry.expiry <= now))) {
lib_plankton.log.info("plankton.cache.unknown_or_expired", {
"key": key,
});
return (retrieve()
.then((value) => (subject.write(key, {
"value": value,
"expiry": ((lifetime === null)
?
null
:
(now + lifetime))
})
.then(() => Promise.resolve({
"retrieved": true,
"value": value
})))));
}
else {
lib_plankton.log.info("plankton.cache.known_and_valid", {
"key": key,
});
return Promise.resolve({
"retrieved": false,
"value": item.entry.value
});
}
}));
}
cache_1.query = query;
/**
* syntactic sugar: if the information, whether the value was retrieved, is irrelevant
*/
function get(subject, key, lifetime, retrieve) {
return (query(subject, key, lifetime, retrieve)
.then(result => Promise.resolve(result.value)));
}
cache_1.get = get;
/**
*/
function get_complex(cache, group, input, lifetime, retrieve, { "encode_input": encode_input = (input => JSON.stringify(input)), } = {}) {
return get(cache, (group + "." + encode_input(input)), lifetime, () => retrieve(input));
}
cache_1.get_complex = get_complex;
})(cache = lib_plankton.cache || (lib_plankton.cache = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:complex«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
@ -9449,6 +9941,12 @@ var lib_plankton;
* @author fenris
*/
class class_relation {
/**
* @author fenris
*/
check(value, reference) {
return this.predicate(value, reference);
}
/**
* @author fenris
*/
@ -9458,12 +9956,6 @@ var lib_plankton;
this.name = name;
this.predicate = predicate;
}
/**
* @author fenris
*/
check(value, reference) {
return this.predicate(value, reference);
}
/**
* @author fenris
*/
@ -9940,7 +10432,7 @@ var lib_plankton;
h = 0;
}
else if (q === r) {
h = ((0 / 3) + ((g - b) / (c * 6)));
h = ((0 / 3) + lib_plankton.math.mod((g - b) / (c * 6), 1));
}
else if (q === g) {
h = ((1 / 3) + ((b - r) / (c * 6)));
@ -11738,190 +12230,6 @@ var lib_plankton;
})(translate = lib_plankton.translate || (lib_plankton.translate = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:zoo-page«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:zoo-page« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»bacterio-plankton:zoo-page« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:zoo-page«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var zoo_page;
(function (zoo_page) {
/**
*/
zoo_page._pool = {};
/**
*/
let _fallback = null;
/**
*/
let _current = null;
/**
*/
let _target_element = null;
/**
*/
let _nav_entries;
/**
*/
function encode(location) {
return ("#"
+
([location.name]
.concat(Object.entries(location.parameters)
.filter(([key, value]) => (value !== null))
.map(([key, value]) => (key + "=" + value)))));
}
zoo_page.encode = encode;
/**
*/
function decode(encoded) {
if (encoded === "") {
return null;
}
else {
if (!encoded.startsWith("#")) {
return null;
}
else {
const parts = encoded.slice(1).split(",");
return {
"name": parts[0],
"parameters": Object.fromEntries(parts.slice(1)
.map(part => {
const parts_ = part.split("=");
return [parts_[0], parts_[1]];
})),
};
}
}
}
/**
* renders a page to the main element
*/
async function load(location) {
// _target_element.innerHTML = "[loading …]";
_target_element.innerHTML = "";
if (location === null) {
// do nothing
}
else {
if (!(location.name in zoo_page._pool)) {
_target_element.innerHTML = "not found";
}
else {
await zoo_page._pool[location.name](location.parameters, _target_element);
_current = location;
}
}
}
/**
* retrieves the location from the set URL
*/
function get() {
return decode(window.location.hash);
}
/**
* encodes a location in the URL and loads it
*/
function set(location) {
window.location.hash = encode(location);
}
zoo_page.set = set;
/**
*/
function reload() {
return load(get());
}
zoo_page.reload = reload;
/**
*/
function register(location_name, handler) {
zoo_page._pool[location_name] = handler;
}
zoo_page.register = register;
/**
*/
function nav_set_groups(groups) {
_nav_entries.forEach(nav_entry => {
const active = ((groups === null)
||
groups.some(group => nav_entry.definition.groups.includes(group)));
nav_entry.element.classList.toggle("active", active);
});
}
zoo_page.nav_set_groups = nav_set_groups;
/**
*/
function init(target_element, { "pool": pool = {}, "fallback": fallback = null, "nav_entries": nav_entries = [], "nav_initial_groups": nav_initial_groups = null, } = {}) {
_target_element = target_element;
_fallback = fallback;
Object.entries(pool).forEach(([location_name, handler]) => {
register(location_name, handler);
});
window.addEventListener("hashchange", () => {
const location_old = _current;
const location_new = (get() ?? _fallback);
if (((location_old === null)
&&
(location_new !== null))
||
((location_old !== null)
&&
(location_new !== null)
&&
(location_old.name !== location_new.name))) {
load(location_new);
}
else {
// do nothing
}
});
// nav
{
let ul_element = document.querySelector("nav > ul");
_nav_entries = nav_entries.map(nav_entry_definition => {
let li_element = document.createElement("li");
{
let a_element = document.createElement("a");
a_element.setAttribute("href", encode(nav_entry_definition.location));
a_element.textContent = (nav_entry_definition.label ?? nav_entry_definition.location.name);
li_element.appendChild(a_element);
}
ul_element.appendChild(li_element);
return {
"definition": nav_entry_definition,
"element": li_element,
};
});
nav_set_groups(nav_initial_groups);
}
}
zoo_page.init = init;
/**
*/
function start() {
const location = (get() ?? _fallback);
set(location);
load(location);
}
zoo_page.start = start;
})(zoo_page = lib_plankton.zoo_page || (lib_plankton.zoo_page = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:zoo-widget«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
@ -12441,6 +12749,190 @@ var lib_plankton;
})(zoo_widget = lib_plankton.zoo_widget || (lib_plankton.zoo_widget = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:zoo-page«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>
»bacterio-plankton:zoo-page« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
»bacterio-plankton:zoo-page« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:zoo-page«. If not, see <http://www.gnu.org/licenses/>.
*/
var lib_plankton;
(function (lib_plankton) {
var zoo_page;
(function (zoo_page) {
/**
*/
zoo_page._pool = {};
/**
*/
let _fallback = null;
/**
*/
let _current = null;
/**
*/
let _target_element = null;
/**
*/
let _nav_entries;
/**
*/
function encode(location) {
return ("#"
+
([location.name]
.concat(Object.entries(location.parameters)
.filter(([key, value]) => (value !== null))
.map(([key, value]) => (key + "=" + value)))));
}
zoo_page.encode = encode;
/**
*/
function decode(encoded) {
if (encoded === "") {
return null;
}
else {
if (!encoded.startsWith("#")) {
return null;
}
else {
const parts = encoded.slice(1).split(",");
return {
"name": parts[0],
"parameters": Object.fromEntries(parts.slice(1)
.map(part => {
const parts_ = part.split("=");
return [parts_[0], parts_[1]];
})),
};
}
}
}
/**
* renders a page to the main element
*/
async function load(location) {
// _target_element.innerHTML = "[loading …]";
_target_element.innerHTML = "";
if (location === null) {
// do nothing
}
else {
if (!(location.name in zoo_page._pool)) {
_target_element.innerHTML = "not found";
}
else {
await zoo_page._pool[location.name](location.parameters, _target_element);
_current = location;
}
}
}
/**
* retrieves the location from the set URL
*/
function get() {
return decode(window.location.hash);
}
/**
* encodes a location in the URL and loads it
*/
function set(location) {
window.location.hash = encode(location);
}
zoo_page.set = set;
/**
*/
function reload() {
return load(get());
}
zoo_page.reload = reload;
/**
*/
function register(location_name, handler) {
zoo_page._pool[location_name] = handler;
}
zoo_page.register = register;
/**
*/
function nav_set_groups(groups) {
_nav_entries.forEach(nav_entry => {
const active = ((groups === null)
||
groups.some(group => nav_entry.definition.groups.includes(group)));
nav_entry.element.classList.toggle("active", active);
});
}
zoo_page.nav_set_groups = nav_set_groups;
/**
*/
function init(target_element, { "pool": pool = {}, "fallback": fallback = null, "nav_entries": nav_entries = [], "nav_initial_groups": nav_initial_groups = null, } = {}) {
_target_element = target_element;
_fallback = fallback;
Object.entries(pool).forEach(([location_name, handler]) => {
register(location_name, handler);
});
window.addEventListener("hashchange", () => {
const location_old = _current;
const location_new = (get() ?? _fallback);
if (((location_old === null)
&&
(location_new !== null))
||
((location_old !== null)
&&
(location_new !== null)
&&
(location_old.name !== location_new.name))) {
load(location_new);
}
else {
// do nothing
}
});
// nav
{
let ul_element = document.querySelector("nav > ul");
_nav_entries = nav_entries.map(nav_entry_definition => {
let li_element = document.createElement("li");
{
let a_element = document.createElement("a");
a_element.setAttribute("href", encode(nav_entry_definition.location));
a_element.textContent = (nav_entry_definition.label ?? nav_entry_definition.location.name);
li_element.appendChild(a_element);
}
ul_element.appendChild(li_element);
return {
"definition": nav_entry_definition,
"element": li_element,
};
});
nav_set_groups(nav_initial_groups);
}
}
zoo_page.init = init;
/**
*/
function start() {
const location = (get() ?? _fallback);
set(location);
load(location);
}
zoo_page.start = start;
})(zoo_page = lib_plankton.zoo_page || (lib_plankton.zoo_page = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:zoo-input«.
Copyright 2016-2024 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'

View file

@ -8,6 +8,6 @@
},
"misc": {
"oidc_redirect_uri_template": "http://localhost:8888/#oidc_finish,session_key={{session_key}}",
"use_central_europe_specific_datetime_inputs": false
"use_central_europe_specific_datetime_inputs": true
}
}

117
source/base.ts Normal file
View file

@ -0,0 +1,117 @@
namespace _dali
{
/**
*/
let _actions_login : Array<((name ?: (null | string)) => Promise<void>)> = [];
/**
*/
let _actions_logout : Array<(() => Promise<void>)> = [];
/**
*/
let _is_logged_in : boolean = false;
/**
*/
export function listen_login(
action : ((name ?: (null | string)) => Promise<void>)
)
: void
{
_actions_login.push(action);
}
/**
*/
export function listen_logout(
action : (() => Promise<void>)
)
: void
{
_actions_logout.push(action);
}
/**
*/
export async function notify_login(
name : (null | string)
)
: Promise<void>
{
_is_logged_in = true;
for (const action of _actions_login)
{
await action(name);
}
}
/**
*/
export async function notify_logout(
)
: Promise<void>
{
_is_logged_in = false;
for (const action of _actions_logout)
{
await action();
}
}
/**
*/
export function is_logged_in(
)
: boolean
{
return _is_logged_in;
}
/**
*/
export async function oidc_finish(
session_key : string
)
: Promise<void>
{
await _dali.backend.set_session_key(session_key);
const status = await _dali.backend.status();
await _dali.notify_login(status.name);
return Promise.resolve<void>(undefined);
}
/**
*/
export async function logout(
)
: Promise<void>
{
try
{
await _dali.backend.session_end(
);
notify_logout();
}
catch (error)
{
lib_plankton.log.notice(
"dali.logout_failed",
{
"reason": String(error),
}
);
}
}
}

View file

@ -1,63 +0,0 @@
namespace _dali
{
/**
*/
export function view_mode_encode(
mode : _dali.type.enum_view_mode
) : string
{
switch (mode)
{
case _dali.type.enum_view_mode.week: {return "week"; break;}
case _dali.type.enum_view_mode.list: {return "list"; break;}
default: {throw (new Error("invalid mode"));}
}
}
/**
*/
export function view_mode_decode(
view_mode_encoded : string
) : _dali.type.enum_view_mode
{
const map : Record<string, _dali.type.enum_view_mode> = {
"week": _dali.type.enum_view_mode.week,
"list": _dali.type.enum_view_mode.list,
};
if (! (view_mode_encoded in map))
{
throw (new Error("invalid mode: " + view_mode_encoded));
}
else
{
return map[view_mode_encoded];
}
}
/**
*/
export function view_mode_determine(
mode_descriptor : string
) : _dali.type.enum_view_mode
{
if (mode_descriptor === "auto")
{
return (
(window.innerWidth >= 800)
?
_dali.type.enum_view_mode.week
:
_dali.type.enum_view_mode.list
);
}
else
{
return view_mode_decode(mode_descriptor);
}
}
}

View file

@ -1,124 +0,0 @@
/**
*/
namespace _dali.type
{
/**
*/
export enum enum_access_level {
none,
view,
edit,
admin
}
/**
*/
export type user_id = int;
/**
*/
export type user_object = {
name : string;
email_address : (
null
|
string
);
};
/**
*/
export type event_object = {
name : string;
begin : lib_plankton.pit.type_datetime;
end : (
null
|
lib_plankton.pit.type_datetime
);
location : (
null
|
string
);
link : (
null
|
string
);
description : (
null
|
string
);
};
/**
*/
export type local_resource_event_id = int;
/**
*/
export type resource_id = int;
/**
*/
export type resource_object = (
{
kind : "local";
data : {
events : Array<
event_object
>;
};
}
|
{
kind : "caldav";
data : {
read_only : boolean;
url : string;
};
}
);
/**
*/
export type calendar_id = int;
/**
*/
export type calendar_object = {
name : string;
hue : float;
access : {
public : boolean;
default_level : enum_access_level;
attributed : lib_plankton.map.type_map<
user_id,
enum_access_level
>;
};
resource : resource_object;
};
/**
*/
export enum enum_view_mode
{
week,
list,
}
}

View file

@ -1,18 +0,0 @@
namespace _dali
{
/**
* @todo outsource
*/
export abstract class class_widget
{
/**
*/
public abstract load(
target_element : Element
) : Promise<void>;
}
}

View file

@ -18,6 +18,9 @@
"common.edit": "bearbeiten",
"common.show": "zeigen",
"common.hide": "ausblenden",
"common.cancel": "abbrechen",
"common.login": "anmelden",
"common.logout": "abmelden",
"access_level.none": "nichts",
"access_level.view": "nur lesen",
"access_level.edit": "lesen und bearbeiten",
@ -49,12 +52,17 @@
"widget.weekview.controls.week": "Woche",
"widget.weekview.controls.count": "Anzahl",
"widget.weekview.controls.apply": "Laden",
"page.login.title": "Anmelden",
"page.login.internal.name": "Name",
"page.login.internal.password": "Kennwort",
"page.login.internal.do": "Anmelden",
"page.login.oidc.via": "via {{title}}",
"page.logout.title": "Abmelden",
"widget.calendar_edit.actions.add": "Kalender anlegen",
"widget.calendar_edit.actions.change": "ändern",
"widget.calendar_edit.actions.remove": "löschen",
"widget.event_edit.actions.add": "anlegen",
"widget.event_edit.actions.change": "ändern",
"widget.event_edit.actions.remove": "löschen",
"widget.sources.create": "Kalender anlegen",
"widget.login.internal.name": "Name",
"widget.login.internal.password": "Kennwort",
"widget.login.internal.do": "Anmelden",
"widget.login.oidc.via": "via {{title}}",
"page.caldav.title": "CalDAV",
"page.caldav.unavailable": "CalDAV nicht verfügbar",
"page.caldav.conf.title": "Zugangsdaten",
@ -70,14 +78,9 @@
"page.calendar_add.actions.do": "anlegen",
"page.calendar_edit.title.regular": "Kalendar bearbeiten",
"page.calendar_edit.title.read_only": "Kalendar-Details",
"page.calendar_edit.actions.change": "ändern",
"page.calendar_edit.actions.remove": "löschen",
"page.event_add.title": "Termin anlegen",
"page.event_add.actions.do": "anlegen",
"page.event_edit.title.regular": "Termin bearbeiten",
"page.event_edit.title.read_only": "Termin-Details",
"page.event_edit.actions.change": "ändern",
"page.event_edit.actions.remove": "löschen",
"page.overview.title": "Übersicht",
"page.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen",
"page.overview.mode.week": "Wochen-Ansicht",

View file

@ -18,6 +18,9 @@
"common.edit": "edit",
"common.show": "show",
"common.hide": "hide",
"common.cancel": "cancel",
"common.login": "login",
"common.logout": "logout",
"access_level.none": "none",
"access_level.view": "read only",
"access_level.edit": "read and write",
@ -36,7 +39,7 @@
"resource.kinds.caldav.title": "CalDAV",
"resource.kinds.caldav.url": "URL",
"resource.kinds.caldav.read_only": "read-only",
"calendar.calendar": "Kalendar",
"calendar.calendar": "calendar",
"calendar.name": "name",
"calendar.hue": "hue",
"calendar.resource": "resource",
@ -49,12 +52,17 @@
"widget.weekview.controls.week": "Week",
"widget.weekview.controls.count": "Count",
"widget.weekview.controls.apply": "Load",
"page.login.title": "Login",
"page.login.internal.name": "name",
"page.login.internal.password": "password",
"page.login.internal.do": "login",
"page.login.oidc.via": "via {{title}}",
"page.logout.title": "Logout",
"widget.calendar_edit.actions.add": "add calendar",
"widget.calendar_edit.actions.change": "change",
"widget.calendar_edit.actions.remove": "delete",
"widget.event_edit.actions.add": "add",
"widget.event_edit.actions.change": "change",
"widget.event_edit.actions.remove": "delete",
"widget.sources.create": "create calendar",
"widget.login.internal.name": "name",
"widget.login.internal.password": "password",
"widget.login.internal.do": "login",
"widget.login.oidc.via": "via {{title}}",
"page.caldav.title": "CalDAV",
"page.caldav.unavailable": "CalDAV not available",
"page.caldav.conf.title": "credentials",
@ -69,15 +77,10 @@
"page.calendar_add.title": "Add calendar",
"page.calendar_add.actions.do": "anlegen",
"page.event_add.title": "Add event",
"page.event_add.actions.do": "add",
"page.calendar_edit.title.regular": "Edit calendar",
"page.calendar_edit.title.read_only": "Calendar details",
"page.calendar_edit.actions.change": "change",
"page.calendar_edit.actions.remove": "delete",
"page.event_edit.title.regular": "Edit event",
"page.event_edit.title.read_only": "Event details",
"page.event_edit.actions.change": "change",
"page.event_edit.actions.remove": "delete",
"page.overview.title": "Overview",
"page.overview.login_hint": "log in to view non-public events",
"page.overview.mode.week": "week view",

View file

@ -9,6 +9,29 @@ namespace _dali.helpers
var _template_cache : Record<string, string> = {};
/**
*/
export function view_mode_determine(
mode_descriptor : string
) : _dali.enum_view_mode
{
if (mode_descriptor === "auto")
{
return (
(window.innerWidth >= 800)
?
_dali.enum_view_mode.week
:
_dali.enum_view_mode.list
);
}
else
{
return view_mode_decode(mode_descriptor);
}
}
/**
*/
export async function template_coin(
@ -78,12 +101,12 @@ namespace _dali.helpers
/**
*/
export function input_access_level(
) : lib_plankton.zoo_input.interface_input<_dali.type.enum_access_level>
) : lib_plankton.zoo_input.interface_input<_dali.enum_access_level>
{
return (
new lib_plankton.zoo_input.class_input_wrapped<
/*("none" | "view" | "edit" | "admin")*/string,
_dali.type.enum_access_level
_dali.enum_access_level
>(
new lib_plankton.zoo_input.class_input_selection(
[
@ -107,18 +130,18 @@ namespace _dali.helpers
),
(raw) => {
switch (raw) {
case "none": return _dali.type.enum_access_level.none;
case "view": return _dali.type.enum_access_level.view;
case "edit": return _dali.type.enum_access_level.edit;
case "admin": return _dali.type.enum_access_level.admin;
case "none": return _dali.enum_access_level.none;
case "view": return _dali.enum_access_level.view;
case "edit": return _dali.enum_access_level.edit;
case "admin": return _dali.enum_access_level.admin;
}
},
(access_level) => {
switch (access_level) {
case _dali.type.enum_access_level.none: return "none";
case _dali.type.enum_access_level.view: return "view";
case _dali.type.enum_access_level.edit: return "edit";
case _dali.type.enum_access_level.admin: return "admin";
case _dali.enum_access_level.none: return "none";
case _dali.enum_access_level.view: return "view";
case _dali.enum_access_level.edit: return "edit";
case _dali.enum_access_level.admin: return "admin";
}
},
)
@ -128,13 +151,16 @@ namespace _dali.helpers
/**
*/
export async function input_attributed_access(
) : Promise<lib_plankton.zoo_input.class_input_hashmap<_dali.type.user_id, _dali.type.enum_access_level>>
export function input_attributed_access(
users : Array<{id : _dali.type_user_id; name : string;}>
)
: lib_plankton.zoo_input.class_input_hashmap<
_dali.type_user_id,
_dali.enum_access_level
>
{
const users : Array<{id : _dali.type.user_id; name : string;}> = await _dali.backend.user_list(
);
return Promise.resolve(
new lib_plankton.zoo_input.class_input_hashmap<_dali.type.user_id, _dali.type.enum_access_level>(
return (
new lib_plankton.zoo_input.class_input_hashmap<_dali.type_user_id, _dali.enum_access_level>(
// hash_key
(user_id) => user_id.toFixed(0),
// key_input_factory

View file

@ -24,12 +24,12 @@ document.addEventListener(
</script>
{{templates}}
</head>
<div id="overlay">
<div id="overlay_content">
</div>
</div>
<body>
<header>
<nav>
<ul>
</ul>
</nav>
</header>
<main>
</main>

View file

@ -8,7 +8,8 @@ namespace _dali
*/
function nav_groups(
logged_in : boolean
) : Array<string>
)
: Array<string>
{
return (
logged_in
@ -24,12 +25,13 @@ namespace _dali
* @todo reload page when switching to "logged_out"
*/
async function update(
) : Promise<void>
)
: Promise<void>
{
lib_plankton.log.debug(
"dali.update"
);
const logged_in : boolean = await _dali.backend.is_logged_in();
const logged_in : boolean = _dali.is_logged_in();
lib_plankton.zoo_page.nav_set_groups(nav_groups(logged_in));
// lib_plankton.zoo_page.reload();
}
@ -38,7 +40,8 @@ namespace _dali
/**
*/
export async function main(
) : Promise<void>
)
: Promise<void>
{
// conf
await _dali.conf.init(
@ -51,8 +54,6 @@ namespace _dali
{"kind": "console", "data": {"threshold": "info"}},
]
);
await _dali.backend.init(
);
await lib_plankton.translate.initialize(
{
"verbosity": 1,
@ -64,6 +65,11 @@ namespace _dali
"autopromote": false,
}
);
await _dali.backend.initialize(
_dali.conf.get()["backend"]
);
await _dali.model.initialize(
);
lib_plankton.zoo_page.init(
document.querySelector("main"),
{
@ -71,52 +77,115 @@ namespace _dali
"name": "overview",
"parameters": {}
},
"nav_entries": [
{
"location": {"name": "login", "parameters": {}},
"label": lib_plankton.translate.get("page.login.title"),
"groups": ["logged_out"],
},
{
"location": {"name": "overview", "parameters": {}},
"label": lib_plankton.translate.get("page.overview.title"),
"groups": ["logged_out", "logged_in"],
},
{
"location": {"name": "calendar_add", "parameters": {}},
"label": lib_plankton.translate.get("page.calendar_add.title"),
"groups": ["logged_in"],
},
{
"location": {"name": "caldav", "parameters": {}},
"label": lib_plankton.translate.get("page.caldav.title"),
"groups": ["logged_in"],
},
/*
{
"location": {"name": "event_add", "parameters": {}},
"label": lib_plankton.translate.get("page.event_add.title"),
"groups": ["logged_in"],
}
*/
{
"location": {"name": "logout", "parameters": {}},
"label": lib_plankton.translate.get("page.logout.title"),
"groups": ["logged_in"],
},
"nav_entries": [
],
*/
"nav_initial_groups": [],
}
);
// menu widget
{
const widget_menu : _dali.widgets.menu.class_widget_menu = new _dali.widgets.menu.class_widget_menu(
[
{
"label": lib_plankton.translate.get("common.login"),
"groups": ["logged_out"],
"action": () => {
const widget_login = new _dali.widgets.login.class_widget_login(
{
"action_cancel": () => {
_dali.overlay.clear();
_dali.overlay.toggle({"mode": false});
},
"action_success": async () => {
const status = await _dali.backend.status();
_dali.notify_login(status.name);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": false});
},
}
);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": true});
widget_login.load(_dali.overlay.get_content_element());
},
},
{
"label": lib_plankton.translate.get("page.overview.title"),
"groups": ["logged_out", "logged_in"],
"action": () => {
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
},
},
{
"label": lib_plankton.translate.get("page.caldav.title"),
"groups": ["logged_in"],
"action": () => {
lib_plankton.zoo_page.set(
{
"name": "caldav",
"parameters": {}
}
);
},
},
{
"label": lib_plankton.translate.get("common.logout"),
"groups": ["logged_in"],
"action": () => {
_dali.logout();
},
},
]
);
await widget_menu.load(document.querySelector("header"));
_dali.listen_login(
async (name) => {
widget_menu.set_groups(["logged_in"]);
widget_menu.set_label(name);
}
);
_dali.listen_logout(
async () => {
widget_menu.set_groups(["logged_out"]);
widget_menu.set_label(null);
}
);
}
await update();
await _dali.overlay.initialize();
/*
lib_plankton.call.loop(
() => {
update();
},
_dali.conf.get().misc.update_interval
);
*/
// check if logged_in
{
const status = await _dali.backend.status();
lib_plankton.log.info(
"dali.status",
status
);
if (status.logged_in)
{
_dali.notify_login(status.name);
}
else
{
_dali.notify_logout();
}
}
// exec
lib_plankton.zoo_page.start();
return Promise.resolve<void>(undefined);

604
source/model.ts Normal file
View file

@ -0,0 +1,604 @@
namespace _dali.model
{
/**
*/
type type_state = {
users : Array<
{
id : _dali.type_user_id;
name : string;
}
>;
calendars : (
null
|
lib_plankton.map.type_map<
_dali.type_calendar_id,
{
reduced : _dali.type_calendar_object_reduced;
complete : (null | _dali.type_calendar_object);
}
>
);
events : lib_plankton.map.type_map<
_dali.type_event_key,
_dali.type_event_object_extended
>;
covered_dates : lib_plankton.set.type_set<
lib_plankton.pit.type_date
>;
};
/**
*/
let _state : (null | type_state) = null;
/**
*/
let _listeners_reset : Array<((priviliged ?: boolean) => Promise<void>)> = [];
/**
*/
function make_date_set(
{
"elements": elements = [],
}
:
{
elements ?: Array<lib_plankton.pit.type_date>;
}
=
{
}
)
: lib_plankton.set.type_set<lib_plankton.pit.type_date>
{
return lib_plankton.set.hashset.implementation_set(
lib_plankton.set.hashset.make(
x => lib_plankton.pit.date_format(x),
{
/**
* @todo häääh!?
*/
"elements": elements.filter(x => (x !== null)),
}
)
);
}
/**
*/
function timeframe_to_date_set(
timeframe : {
from : lib_plankton.pit.type_pit;
to : lib_plankton.pit.type_pit;
}
)
: lib_plankton.set.type_set<lib_plankton.pit.type_date>
{
if (! lib_plankton.pit.is_before(timeframe.from, timeframe.to))
{
throw (new Error("invalid timeframe"));
}
else
{
const heuristic : int = Math.ceil((timeframe.to - timeframe.from) / (60 * 60 * 24));
let pit_current : lib_plankton.pit.type_pit = timeframe.from;
return make_date_set(
{
"elements": (
lib_plankton.list.sequence(heuristic)
.map(
(offset) => lib_plankton.call.convey(
timeframe.from,
[
x => lib_plankton.pit.shift_day(x, offset),
x => lib_plankton.pit.to_datetime(x),
x => x.date,
]
)
)
),
}
);
}
}
/**
*/
export async function user_list(
)
: Promise<
Array<
{
id : _dali.type_user_id;
name : string;
}
>
>
{
return Promise.resolve(_state.users);
}
/**
* @todo clear after login/logout
* @todo do not export
*/
export async function sync_calendars(
)
: Promise<void>
{
const data = await _dali.backend.calendar_list();
lib_plankton.map.clear(_state.calendars);
data.forEach(
entry => {
_state.calendars.set(
entry.id,
{
"reduced": {
"name": entry.name,
"hue": entry.hue,
"access_level": _dali.access_level_decode(entry.access_level),
},
"complete": null,
}
);
}
);
}
/**
*/
export function calendar_list(
)
: Promise<
Array<
_dali.type_calendar_object_reduced_with_id
>
>
{
return Promise.resolve(
lib_plankton.map.dump(_state.calendars)
.map(
pair => (
{
"id": pair.key,
"name": pair.value.reduced.name,
"hue": pair.value.reduced.hue,
"access_level": pair.value.reduced.access_level,
}
)
)
);
}
/**
*/
export async function calendar_get(
calendar_id : _dali.type_calendar_id
)
: Promise<_dali.type_calendar_object>
{
const value = _state.calendars.get(calendar_id);
if (value.complete === null)
{
const data = await _dali.backend.calendar_get(calendar_id);
const calendar_object : _dali.type_calendar_object = {
"name": data.name,
"hue": data.hue,
"access": {
"public": data.access.public,
"default_level": _dali.access_level_decode(data.access.default_level),
"attributed": lib_plankton.map.hashmap.implementation_map(
lib_plankton.map.hashmap.make(
x => x.toFixed(0),
{
"pairs": (
data.access.attributed
.map(
(entry) => (
{
"key": entry.user_id,
"value": _dali.access_level_decode(entry.level),
}
)
)
),
}
)
),
},
"resource_id": data.resource_id,
};
value.complete = calendar_object;
/**
* @todo set in map?
*/
return calendar_object;
}
else
{
return value.complete;
}
}
/**
*/
export async function calendar_add(
calendar_object : _dali.type_calendar_object
)
: Promise<void>
{
const calendar_id : _dali.type_calendar_id = await _dali.backend.calendar_add(
{
"name": calendar_object.name,
"hue": calendar_object.hue,
"access": {
"public": calendar_object.access.public,
"default_level": _dali.access_level_encode(calendar_object.access.default_level),
"attributed": (
lib_plankton.map.dump(calendar_object.access.attributed)
.map(
(pair) => (
{
"user_id": pair.key,
"level": _dali.access_level_encode(pair.value),
}
)
)
)
},
/**
* @todo
*/
"resource": {
"kind": "local",
"data": {
"events": [],
}
},
}
);
const calendar_object_reduced : _dali.type_calendar_object_reduced = {
"name": calendar_object.name,
"hue": calendar_object.hue,
"access_level": _dali.enum_access_level.admin,
};
_state.calendars.set(
calendar_id,
{
"reduced": calendar_object_reduced,
"complete": calendar_object,
}
);
}
/**
*/
export async function calendar_change(
calendar_id : _dali.type_calendar_id,
calendar_object : _dali.type_calendar_object
)
: Promise<void>
{
/*await */ _dali.backend.calendar_change(
calendar_id,
{
"name": calendar_object.name,
"hue": calendar_object.hue,
"access": {
"public": calendar_object.access.public,
"default_level": _dali.access_level_encode(calendar_object.access.default_level),
"attributed": (
lib_plankton.map.dump(calendar_object.access.attributed)
.map(
(pair) => ({
"user_id": pair.key,
"level": _dali.access_level_encode(pair.value),
})
)
)
},
}
);
const calendar_object_reduced : _dali.type_calendar_object_reduced = {
"name": calendar_object.name,
"hue": calendar_object.hue,
/**
* @todo
*/
"access_level": _dali.enum_access_level.admin,
};
_state.calendars.set(
calendar_id,
{
"reduced": calendar_object_reduced,
"complete": calendar_object,
}
);
{
lib_plankton.map.clear(_state.events);
lib_plankton.set.clear(_state.covered_dates);
notify_reset();
}
}
/**
*/
export async function calendar_remove(
calendar_id : _dali.type_calendar_id
)
: Promise<void>
{
/*await */ _dali.backend.calendar_remove(calendar_id);
_state.calendars.delete(calendar_id);
{
lib_plankton.map.clear(_state.events);
lib_plankton.set.clear(_state.covered_dates);
notify_reset();
}
}
/**
* @todo do NOT export?
* @todo clear?
* @todo heed calendar_ids
* @todo mutex
* @todo only update outside timeframe
* @todo clear after login/logout
*/
export async function sync_events(
timeframe : {
from : lib_plankton.pit.type_pit;
to : lib_plankton.pit.type_pit;
},
{
"calendar_ids": calendar_ids = null,
}
:
{
calendar_ids ?: (null | Array<_dali.type_calendar_id>);
}
=
{
}
)
: Promise<void>
{
const queried_dates : lib_plankton.set.type_set<lib_plankton.pit.type_date> = timeframe_to_date_set(
timeframe
);
const new_dates : lib_plankton.set.type_set<lib_plankton.pit.type_date> = lib_plankton.set.difference(
() => make_date_set(),
queried_dates,
_state.covered_dates
);
if (lib_plankton.set.empty(new_dates))
{
// do nothing
}
else
{
const result = await _dali.backend.events(
timeframe.from,
timeframe.to,
{
"calendar_ids": calendar_ids,
}
);
result.forEach(
entry => {
_state.events.set(
entry.hash,
{
"key": entry.hash,
"calendar_id": entry.calendar_id,
"calendar_name": entry.calendar_name,
"hue": entry.hue,
"access_level": _dali.access_level_decode(entry.access_level),
"event_id": entry.event_id,
"event_object": entry.event_object
}
);
}
);
_state.covered_dates = lib_plankton.set.union(
() => make_date_set(),
_state.covered_dates,
new_dates
);
}
}
/**
*/
export function event_list(
)
: Promise<Array<_dali.type_event_object_extended>>
{
return Promise.resolve(lib_plankton.map.values(_state.events));
}
/**
*/
export async function event_get(
event_key : _dali.type_event_key
)
: Promise<_dali.type_event_object_extended>
{
return Promise.resolve(_state.events.get(event_key));
}
/**
*/
export async function event_add(
calendar_id : _dali.type_calendar_id,
event_object : _dali.type_event_object
)
: Promise<void>
{
/**
* @todo do NOT wait?
*/
const result = await _dali.backend.calendar_event_add(
calendar_id,
event_object
);
const event_id : _dali.type_local_resource_event_id = result.local_resource_event_id;
const event_key : _dali.type_event_key = result.hash;
const value = _state.calendars.get(calendar_id);
const calendar_object_reduced : _dali.type_calendar_object_reduced = value.reduced;
_state.events.set(
event_key,
{
"key": event_key,
"calendar_id": calendar_id,
"calendar_name": calendar_object_reduced.name,
"hue": calendar_object_reduced.hue,
"access_level": calendar_object_reduced.access_level,
"event_id": event_id,
"event_object": event_object,
}
);
}
/**
*/
export async function event_change(
event_key : _dali.type_event_key,
event_object : _dali.type_event_object
)
: Promise<void>
{
const event_object_extended_old : _dali.type_event_object_extended = _state.events.get(event_key);
const event_object_extended_new : _dali.type_event_object_extended = {
"key": event_object_extended_old.key,
"calendar_id": event_object_extended_old.calendar_id,
"calendar_name": event_object_extended_old.calendar_name,
"hue": event_object_extended_old.hue,
"access_level": event_object_extended_old.access_level,
"event_id": event_object_extended_old.event_id,
"event_object": event_object,
};
_state.events.set(
event_key,
event_object_extended_new
);
/*await */_dali.backend.calendar_event_change(
event_object_extended_old.calendar_id,
event_object_extended_old.event_id,
event_object
);
}
/**
*/
export async function event_remove(
event_key : _dali.type_event_key
)
: Promise<void>
{
const event_object_extended : _dali.type_event_object_extended = _state.events.get(event_key);
_state.events.delete(event_key);
/*await */_dali.backend.calendar_event_remove(
event_object_extended.calendar_id,
event_object_extended.event_id
);
}
/**
*/
export function listen_reset(
action : ((priviliged ?: boolean) => Promise<void>)
)
: void
{
_listeners_reset.push(action);
}
/**
*/
async function notify_reset(
priviliged ?: boolean
)
: Promise<void>
{
for (const action of _listeners_reset)
{
await action(priviliged);
}
}
/**
*/
export async function initialize(
)
: Promise<void>
{
_state = {
"users": (
_dali.is_logged_in()
?
(await _dali.backend.user_list())
:
[]
),
"calendars": lib_plankton.map.hashmap.implementation_map(
lib_plankton.map.hashmap.make(
calendar_id => calendar_id.toFixed(0)
)
),
"events": lib_plankton.map.hashmap.implementation_map(
lib_plankton.map.hashmap.make(
event_key => event_key
)
),
"covered_dates": make_date_set(
),
};
_dali.listen_login(
async () => {
_state.users = await _dali.backend.user_list();
await sync_calendars();
lib_plankton.map.clear(_state.events);
lib_plankton.set.clear(_state.covered_dates);
notify_reset(true);
}
);
_dali.listen_logout(
async () => {
_state.users = [];
await sync_calendars();
lib_plankton.map.clear(_state.events);
lib_plankton.set.clear(_state.covered_dates);
notify_reset(false);
}
);
await sync_calendars();
// await sync_events();
}
}

75
source/overlay.ts Normal file
View file

@ -0,0 +1,75 @@
namespace _dali.overlay
{
/**
*/
function get_container_element(
) : HTMLElement
{
return document.querySelector("#overlay");
}
/**
*/
export function get_content_element(
) : HTMLElement
{
return document.querySelector("#overlay_content");
}
/**
*/
export function clear(
) : void
{
get_content_element().innerHTML = "";
}
/**
*/
export function toggle(
{
"mode": mode = null,
}
:
{
mode ?: (null | boolean);
}
=
{
}
) : void
{
get_container_element().classList.toggle("overlay_active", mode ?? undefined);
}
/**
*/
export function initialize(
) : Promise<void>
{
clear();
const container_element : HTMLElement = get_container_element();
/*
container_element.addEventListener(
"click",
(event) => {
if (event.target == container_element)
{
toggle({"mode": false});
}
else
{
// do nothing
}
}
);
*/
return Promise.resolve<void>(undefined);
}
}

View file

@ -1,228 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"calendar_add",
async (parameters, target_element) => {
target_element.innerHTML = "";
target_element.innerHTML = await _dali.helpers.template_coin(
"calendar_add",
"default",
{
"label": lib_plankton.translate.get("page.calendar_add.title")
}
);
const form : lib_plankton.zoo_form.class_form<
{
name : string;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
resource_kind : string;
hue : (null | float);
},
{
name : string;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
resource_kind : string;
hue : (null | float);
}
> = new lib_plankton.zoo_form.class_form<
{
name : string;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
resource_kind : string;
hue : (null | float);
},
{
name : string;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
resource_kind : string;
hue : (null | float);
}
>(
(value) => value,
(raw) => raw,
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("calendar.name")
},
{
"name": "hue",
"input": new lib_plankton.zoo_input.class_input_hue(
),
"label": lib_plankton.translate.get("calendar.hue"),
},
{
"name": "access",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "public",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("calendar.access.public"),
},
{
"name": "default_level",
"input": _dali.helpers.input_access_level(),
"label": lib_plankton.translate.get("calendar.access.default_level"),
},
{
"name": "attributed",
"input": await _dali.helpers.input_attributed_access(),
"label": lib_plankton.translate.get("calendar.access.attributed"),
},
]
),
"label": lib_plankton.translate.get("calendar.access.access"),
},
{
"name": "resource_kind",
"input": new lib_plankton.zoo_input.class_input_selection(
[
{
"value": "local",
"label": lib_plankton.translate.get("resource.kinds.local.title")
},
{
"value": "caldav",
"label": lib_plankton.translate.get("resource.kinds.caldav.title")
},
]
),
"label": lib_plankton.translate.get("resource.kind")
},
]
),
[
{
"label": lib_plankton.translate.get("page.calendar_add.actions.do"),
"procedure": async (get_value, get_representation) => {
const value : any = await get_value();
const calendar_object : _dali.type.calendar_object = {
"name": value.name,
"access": {
"public": value.access.public,
"default_level": value.access.default_level,
"attributed": value.access.attributed,
},
"resource": (() => {
switch (value.resource_kind) {
case "local":
{
return {
"kind": "local",
"data": {
"events": [],
}
};
break;
}
case "caldav":
{
return {
"kind": "caldav",
"data": {
"url": "", // TODO
"read_only": true, // TODO
}
};
break;
}
default:
{
throw (new Error("invalid resource kind: " + value.resource_kind));
break;
}
}
}) (),
"hue": value.hue,
};
try
{
await _dali.backend.calendar_add(
calendar_object
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error)
{
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
]
);
await form.setup(document.querySelector("#calendar_add_form"));
await form.input_write(
{
"name": "",
"access": {
"public": false,
"default_level": _dali.type.enum_access_level.view,
"attributed": lib_plankton.map.hashmap.implementation_map<
_dali.type.user_id,
_dali.type.enum_access_level
>(
lib_plankton.map.hashmap.make<
_dali.type.user_id,
_dali.type.enum_access_level
>(
user_id => user_id.toFixed(0),
)
),
},
"resource_kind": "local",
"hue": lib_plankton.random.generate_unit(),
}
);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -1,5 +0,0 @@
<div id="calendar_add">
<h2>{{label}}</h2>
<div id="calendar_add_form">
</div>
</div>

View file

@ -1,187 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"calendar_edit",
async (parameters, target_element) => {
const read_only : boolean = ((parameters["read_only"] ?? "yes") === "yes");
const calendar_id : int = parseInt(parameters["calendar_id"]);
target_element.innerHTML = "";
target_element.innerHTML = await _dali.helpers.template_coin(
"calendar_edit",
"default",
{
"label": lib_plankton.translate.get("page.calendar_edit.title.regular")
}
);
const form : lib_plankton.zoo_form.class_form<
{
name : string;
hue : float;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
},
{
name : string;
hue : float;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
}
> = new lib_plankton.zoo_form.class_form<
{
name : string;
hue : float;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
},
{
name : string;
hue : float;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
>;
};
}
>(
(value) => value,
(raw) => raw,
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("calendar.name")
},
{
"name": "hue",
"input": new lib_plankton.zoo_input.class_input_hue(
),
"label": lib_plankton.translate.get("calendar.hue"),
},
{
"name": "access",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "public",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("calendar.access.public"),
},
{
"name": "default_level",
"input": _dali.helpers.input_access_level(),
"label": lib_plankton.translate.get("calendar.access.default_level"),
},
{
"name": "attributed",
"input": await _dali.helpers.input_attributed_access(),
"label": lib_plankton.translate.get("calendar.access.attributed"),
},
]
),
"label": lib_plankton.translate.get("calendar.access.access"),
},
]
),
(
read_only
?
[
]
:
[
{
"label": lib_plankton.translate.get("page.calendar_edit.actions.change"),
"procedure": async (get_value, get_representation) => {
const data : any = await get_value();
try {
await _dali.backend.calendar_change(
calendar_id,
data
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error) {
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
{
"label": lib_plankton.translate.get("page.calendar_edit.actions.remove"),
"procedure": async (get_value, get_representation) => {
try {
await _dali.backend.calendar_remove(
calendar_id
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error) {
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
]
)
);
await form.setup(document.querySelector("#calendar_edit_form"));
const calendar_object : _dali.type.calendar_object = await _dali.backend.calendar_get(
calendar_id
);
await form.input_write(calendar_object);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -1,5 +0,0 @@
<div id="calendar_edit">
<h2>{{label}}</h2>
<div id="calendar_edit_form">
</div>
</div>

View file

@ -1,235 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"event_add",
async (parameters, target_element) => {
const calendar_id : (null | int) = (
("calendar_id" in parameters)
?
parseInt(parameters["calendar_id"])
:
null
);
const year : (null | int) = (
("year" in parameters)
?
parseInt(parameters["year"])
:
null
);
const month : (null | int) = (
("month" in parameters)
?
parseInt(parameters["month"])
:
null
);
const day : (null | int) = (
("day" in parameters)
?
parseInt(parameters["day"])
:
null
);
const date : lib_plankton.pit.type_date = (
(
(year !== null)
&&
(month !== null)
&&
(day !== null)
)
?
{
"year": year,
"month": month,
"day": day,
}
:
lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date
);
target_element.innerHTML = "";
target_element.innerHTML = await _dali.helpers.template_coin(
"event_add",
"default",
{
"label": lib_plankton.translate.get("page.event_add.title")
}
);
const form : lib_plankton.zoo_form.class_form<
{
calendar_id : _dali.type.calendar_id;
event_object : _dali.type.event_object;
},
{
calendar_id : string;
name : string;
begin : lib_plankton.pit.type_datetime;
end : (null | lib_plankton.pit.type_datetime);
location : (null | string);
link : (null | string);
description : (null | string);
}
> = new lib_plankton.zoo_form.class_form<
{
calendar_id : _dali.type.calendar_id;
event_object : _dali.type.event_object;
},
{
calendar_id : string;
name : string;
begin : lib_plankton.pit.type_datetime;
end : (null | lib_plankton.pit.type_datetime);
location : (null | string);
link : (null | string);
description : (null | string);
}
>(
(value) => ({
"calendar_id": value.calendar_id.toFixed(0),
"name": value.event_object.name,
"begin": value.event_object.begin,
"end": value.event_object.end,
"location": value.event_object.location,
"link": value.event_object.link,
"description": value.event_object.description,
}),
(representation) => ({
"calendar_id": parseInt(representation.calendar_id),
"event_object": {
"name": representation.name,
"begin": representation.begin,
"end": representation.end,
"location": representation.location,
"link": representation.link,
"description": representation.description,
}
}),
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "calendar_id",
"input": new lib_plankton.zoo_input.class_input_selection(
(
(await _dali.backend.calendar_list())
.filter(
(entry) => (
(entry.access_level === _dali.type.enum_access_level.edit)
||
(entry.access_level === _dali.type.enum_access_level.admin)
)
)
.map(
(entry) => ({
"value": entry.id.toFixed(0),
"label": entry.name,
})
)
)
),
"label": lib_plankton.translate.get("calendar.calendar")
},
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(
),
"label": lib_plankton.translate.get("event.name")
},
{
"name": "begin",
"input": _dali.helpers.datetime_input(),
"label": lib_plankton.translate.get("event.begin")
},
{
"name": "end",
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
_dali.helpers.datetime_input()
),
"label": lib_plankton.translate.get("event.end")
},
{
"name": "location",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.location")
},
{
"name": "link",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.link")
},
{
"name": "description",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_textarea(
)
),
"label": lib_plankton.translate.get("event.description")
},
]
),
[
{
"label": lib_plankton.translate.get("page.event_add.actions.do"),
"target": "submit",
"procedure": async (get_value, get_representation) => {
const value : any = await get_value();
try {
await _dali.backend.calendar_event_add(
value.calendar_id,
value.event_object
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error) {
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
]
);
await form.setup(document.querySelector("#event_add_form"));
await form.input_write(
{
"calendar_id": (calendar_id ?? 0),
"event_object": {
"name": "",
"begin": {
"timezone_shift": 0,
"date": date,
"time": null
},
"end": null,
"location": null,
"link": null,
"description": null,
}
}
);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -1,5 +0,0 @@
<div id="event_add">
<h2>{{label}}</h2>
<div id="event_add_form">
</div>
</div>

View file

@ -1,195 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"event_edit",
async (parameters, target_element) => {
const read_only : boolean = ((parameters["read_only"] ?? "yes") === "yes");
const calendar_id : int = parseInt(parameters["calendar_id"]);
const event_id : int = parseInt(parameters["event_id"]);
target_element.innerHTML = "";
target_element.innerHTML = await _dali.helpers.template_coin(
"event_edit",
"default",
{
"label": (
read_only
?
lib_plankton.translate.get("page.event_edit.title.read_only")
:
lib_plankton.translate.get("page.event_edit.title.regular")
)
}
);
const form : lib_plankton.zoo_form.class_form<
_dali.type.event_object,
{
name : string;
begin : lib_plankton.pit.type_datetime;
end : (null | lib_plankton.pit.type_datetime);
location : (null | string);
link : (null | string);
description : (null | string);
}
> = new lib_plankton.zoo_form.class_form<
_dali.type.event_object,
{
name : string;
begin : lib_plankton.pit.type_datetime;
end : (null | lib_plankton.pit.type_datetime);
location : (null | string);
link : (null | string);
description : (null | string);
}
>(
(value) => ({
"name": value.name,
"begin": value.begin,
"end": value.end,
"location": value.location,
"link": value.link,
"description": value.description,
}),
(representation) => ({
"name": representation.name,
"begin": representation.begin,
"end": representation.end,
"location": representation.location,
"link": representation.link,
"description": representation.description,
}),
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(
),
"label": lib_plankton.translate.get("event.name")
},
{
"name": "begin",
"input": _dali.helpers.datetime_input(),
"label": lib_plankton.translate.get("event.begin")
},
{
"name": "end",
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
_dali.helpers.datetime_input()
),
"label": lib_plankton.translate.get("event.end")
},
{
"name": "location",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.location")
},
{
"name": "link",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.link")
},
{
"name": "description",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_textarea(
)
),
"label": lib_plankton.translate.get("event.description")
},
]
),
(
read_only
?
[
]
:
[
{
"label": lib_plankton.translate.get("page.event_edit.actions.change"),
"target": "submit",
"procedure": async (get_value, get_representation) => {
const value : any = await get_value();
try {
await _dali.backend.calendar_event_change(
calendar_id,
event_id,
value
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error) {
lib_plankton.log.warning("page_event_edit_error", {"error": String(error)});
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
{
"label": lib_plankton.translate.get("page.event_edit.actions.remove"),
"target": "submit",
"procedure": async (get_value, get_representation) => {
try {
await _dali.backend.calendar_event_remove(
calendar_id,
event_id
);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error) {
lib_plankton.log.warning("page_event_edit_error", {"error": String(error)});
// do nothing
/*
lib_plankton.zoo_page.set(
{
"name": "event_add",
"parameters": {
}
}
);
*/
}
}
},
]
)
);
await form.setup(document.querySelector("#event_edit_form"));
const event_object : _dali.type.event_object = await _dali.backend.calendar_event_get(
calendar_id,
event_id
);
await form.input_write(
event_object
);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -1,5 +0,0 @@
<div id="event_edit">
<h2>{{label}}</h2>
<div id="event_edit_form">
</div>
</div>

View file

@ -1,118 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"login",
async (parameters, target_element) => {
target_element.innerHTML = "";
const preparation : {kind : string; data : any;} = await _dali.backend.session_prepare(
{
"oidc_redirect_uri_template": _dali.conf.get()["misc"]["oidc_redirect_uri_template"],
}
);
switch (preparation.kind)
{
case "internal":
{
target_element.innerHTML = await _dali.helpers.template_coin(
"login",
"default",
{
}
);
const form : lib_plankton.zoo_form.class_form<
{name : string; password : string;},
{name : string; password : string;}
> = new lib_plankton.zoo_form.class_form<
{name : string; password : string;},
{name : string; password : string;}
>(
x => x,
x => x,
new lib_plankton.zoo_input.class_input_group<
{name : string; password : string;}
>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("page.login.internal.name"),
},
{
"name": "password",
"input": new lib_plankton.zoo_input.class_input_password(),
"label": lib_plankton.translate.get("page.login.internal.password"),
},
]
),
[
{
"label": lib_plankton.translate.get("page.login.internal.do"),
"target": "submit",
"procedure": async (get_value, get_representation) => {
const value : any = await get_value();
try
{
await _dali.backend.session_begin(
value.name,
value.password
);
lib_plankton.zoo_page.nav_set_groups(["logged_in"]);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {}
}
);
}
catch (error)
{
lib_plankton.zoo_page.set(
{
"name": "login",
"parameters": {
"name": value.name,
}
}
);
}
}
},
]
);
await form.setup(document.querySelector("#login"));
await form.input_write(
{
"name": (parameters.name ?? ""),
"password": "",
}
);
break;
}
case "oidc":
{
let element_a : HTMLElement = document.createElement("a");;
element_a.textContent = lib_plankton.string.coin(
lib_plankton.translate.get("page.login.oidc.via"),
{
"title": preparation.data.label,
}
);
element_a.setAttribute("href", preparation.data.url);
target_element.innerHTML = "";
target_element.appendChild(element_a);
break;
}
default:
{
break;
}
}
return Promise.resolve<void>(undefined);
}
);
}

View file

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

View file

@ -1,36 +0,0 @@
namespace _dali.pages
{
/**
*/
lib_plankton.zoo_page.register(
"logout",
async (parameters, target_element) => {
target_element.innerHTML = "";
try
{
await _dali.backend.session_end(
);
}
catch (error)
{
lib_plankton.log.notice(
"dali.logout_failed",
{
"details": String(error),
}
);
}
lib_plankton.zoo_page.nav_set_groups(["logged_out"]);
lib_plankton.zoo_page.set(
{
"name": "overview",
"parameters": {
}
}
);
return Promise.resolve<void>(undefined);
}
);
}

View file

@ -7,7 +7,7 @@ namespace _dali.pages
"oidc_finish",
async (parameters, target_element) => {
target_element.innerHTML = "";
await _dali.backend.set_session_key(parameters["session_key"]);
await _dali.oidc_finish(parameters["session_key"]);
lib_plankton.zoo_page.set(
{
"name": "overview",

View file

@ -7,13 +7,13 @@ namespace _dali.pages.overview
"overview",
async (parameters, target_element) => {
// params
const view_mode : _dali.type.enum_view_mode = view_mode_determine(parameters["mode"] ?? "auto");
const view_mode : _dali.enum_view_mode = _dali.helpers.view_mode_determine(parameters["mode"] ?? "auto");
/**
* @todo ordentlich machen (nicht nur week und list)
*/
const set_view_mode = (view_mode) => {
const compact : boolean = (view_mode !== _dali.type.enum_view_mode.week);
const compact : boolean = (view_mode !== _dali.enum_view_mode.week);
target_element.querySelector("#overview").classList.toggle("overview-compact", compact);
};
@ -27,14 +27,14 @@ namespace _dali.pages.overview
// mode switcher
{
const widget_mode_switcher : _dali.class_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher(
const widget_mode_switcher : lib_plankton.zoo_widget.interface_widget = new _dali.widgets.mode_switcher.class_widget_mode_switcher(
[
{
"mode": _dali.type.enum_view_mode.week,
"mode": _dali.enum_view_mode.week,
"label": lib_plankton.translate.get("page.overview.mode.week"),
},
{
"mode": _dali.type.enum_view_mode.list,
"mode": _dali.enum_view_mode.list,
"label": lib_plankton.translate.get("page.overview.mode.list"),
},
],
@ -57,69 +57,146 @@ namespace _dali.pages.overview
await widget_mode_switcher.load(target_element.querySelector("#overview-mode"));
}
let widget_sources : _dali.widgets.sources.class_widget_sources;
let widget_weekview : _dali.widgets.weekview.class_widget_weekview;
let widget_listview : _dali.widgets.listview.class_widget_listview;
const get_available_calendars = async () => {
return (
(await _dali.model.calendar_list())
.filter(
(entry) => (
(entry.access_level === _dali.enum_access_level.edit)
||
(entry.access_level === _dali.enum_access_level.admin)
)
)
);
}
/**
* @todo update listview
*/
const update_sources_and_entries = async (priviliged = null) => {
await widget_sources.update({"priviliged": priviliged});
await widget_weekview.update_entries();
};
/**
* @todo update listview
*/
const update_entries = async (priviliged = null) => {
await widget_weekview.update_entries();
};
// hint
{
if (! await _dali.backend.is_logged_in())
{
target_element.querySelector("#overview-hint").textContent = lib_plankton.translate.get("page.overview.login_hint");
}
else
{
// do nothing
}
const dom_hint = target_element.querySelector("#overview-hint");
dom_hint.textContent = lib_plankton.translate.get("page.overview.login_hint");
dom_hint.classList.toggle("overview-hint-hidden", _dali.is_logged_in());
}
// sources
{
const data : Array<
widget_sources = new _dali.widgets.sources.class_widget_sources(
_dali.model.calendar_list,
{
id : _dali.type.calendar_id;
name : string;
hue : float;
access_level : _dali.type.enum_access_level;
"initial_priviliged": _dali.is_logged_in(),
"action_create": () => {
(async () => {
const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit(
await _dali.model.user_list(),
{
"read_only": false,
"action_cancel": () => {
_dali.overlay.toggle({"mode": false});
},
"action_add": (calendar_object) => {
_dali.model.calendar_add(
calendar_object
)
.then(
() => {
update_sources_and_entries();
_dali.overlay.toggle({"mode": false});
}
> = await _dali.backend.calendar_list(
)
.catch(
(reason) => {
lib_plankton.log.warning(
"dali.overview.calendar_add_error",
{"reason": String(reason)}
);
const widget_sources = new _dali.widgets.sources.class_widget_sources(
data,
{
}
);
},
"initial_value": null,
}
);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element());
}) ();
},
"action_open": (entry) => {
let read_only : boolean;
switch (entry.access_level)
{
case _dali.type.enum_access_level.none:
case _dali.enum_access_level.none:
{
throw (new Error("this event should not be visible"));
break;
}
case _dali.type.enum_access_level.edit:
case _dali.type.enum_access_level.view:
case _dali.enum_access_level.edit:
case _dali.enum_access_level.view:
{
lib_plankton.zoo_page.set(
{
"name": "calendar_edit",
"parameters": {
"read_only": "yes",
"calendar_id": entry.id,
}
}
);
read_only = true;
break;
}
case _dali.type.enum_access_level.admin:
case _dali.enum_access_level.admin:
{
lib_plankton.zoo_page.set(
{
"name": "calendar_edit",
"parameters": {
"read_only": "no",
"calendar_id": entry.id,
}
}
);
read_only = false;
break;
}
}
(async () => {
const calendar_id : _dali.type_calendar_id = entry.id;
const calendar_object : _dali.type_calendar_object = await _dali.model.calendar_get(
calendar_id
);
const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit(
await _dali.model.user_list(),
{
"read_only": read_only,
"action_cancel": () => {
_dali.overlay.toggle({"mode": false});
},
"action_change": (data) => {
_dali.model.calendar_change(
calendar_id,
data
)
.then(
() => {
update_sources_and_entries();
_dali.overlay.toggle({"mode": false});
}
);
},
"action_remove": (data) => {
_dali.model.calendar_remove(
calendar_id
)
.then(
() => {
update_sources_and_entries();
_dali.overlay.toggle({"mode": false});
}
);
},
"initial_value": calendar_object,
}
);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element());
}) ();
},
"action_toggle_visibility": (entry) => {
widget_weekview.toggle_visibility(entry.id);
@ -131,51 +208,131 @@ namespace _dali.pages.overview
}
// events
{
const get_entries = (from_pit, to_pit, calendar_ids) => _dali.backend.events(
from_pit,
to_pit,
const get_entries = async (from_pit, to_pit, calendar_ids) => {
/**
* @todo do NOT wait?
*/
await _dali.model.sync_events(
{
"from": from_pit,
"to": to_pit,
},
{
"calendar_ids": calendar_ids,
}
);
const action_select_event = (calendar_id, access_level, event_id) => {
/**
* @todo filter
*/
return _dali.model.event_list();
};
const action_select_event = async (event_key) => {
const event_object_extended : _dali.type_event_object_extended = await _dali.model.event_get(event_key);
const calendar_id = event_object_extended.calendar_id;
const access_level = event_object_extended.access_level;
const event_id = event_object_extended.event_id;
/*
if (! _dali.is_logged_in())
{
// do nothing
}
else
{
}
*/
let read_only : boolean;
switch (access_level)
{
case _dali.type.enum_access_level.none:
case _dali.enum_access_level.none:
{
throw (new Error("this event should not be visible"));
break;
}
case _dali.type.enum_access_level.view:
case _dali.enum_access_level.view:
{
lib_plankton.zoo_page.set(
{
"name": "event_edit",
"parameters": {
"read_only": "yes",
"calendar_id": calendar_id,
"event_id": event_id,
}
}
);
read_only = true;
break;
}
case _dali.type.enum_access_level.edit:
case _dali.type.enum_access_level.admin:
case _dali.enum_access_level.edit:
case _dali.enum_access_level.admin:
{
lib_plankton.zoo_page.set(
{
"name": "event_edit",
"parameters": {
"read_only": "no",
"calendar_id": calendar_id,
"event_id": event_id,
}
}
);
read_only = false;
break;
}
}
(async () => {
const event_object : _dali.type_event_object = await _dali.backend.calendar_event_get(
calendar_id,
event_id
);
const widget = new _dali.widgets.event_edit.class_widget_event_edit(
(await get_available_calendars()),
{
"calendar_id": calendar_id,
"event_name": event_object.name,
"event_begin": event_object.begin,
"event_end": event_object.end,
"event_location": event_object.location,
"event_link": event_object.link,
"event_description": event_object.description,
},
{
"read_only": read_only,
"action_cancel": () => {
_dali.overlay.toggle({"mode": false});
},
"action_change": (data) => {
_dali.model.event_change(
event_key,
{
"name": data.event_name,
"begin": data.event_begin,
"end": data.event_end,
"location": data.event_location,
"link": data.event_link,
"description": data.event_description,
}
)
.then(
() => {
update_entries();
_dali.overlay.toggle({"mode": false});
}
)
.catch(
(reason) => {
lib_plankton.log.warning(
"dali.overview.event_change.error",
{"reason": String(reason)}
);
}
);
},
"action_remove": () => {
_dali.model.event_remove(
event_key
)
.then(
() => {
update_entries();
_dali.overlay.toggle({"mode": false});
}
)
.catch(
(reason) => {
lib_plankton.log.warning(
"dali.overview.event_remove_error",
{"reason": String(reason)}
);
}
);
},
}
);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element());
}) ();
};
// listview
{
@ -210,23 +367,98 @@ namespace _dali.pages.overview
{
"action_select_event": action_select_event,
"action_select_day": (date) => {
lib_plankton.zoo_page.set(
/*
if (! _dali.is_logged_in())
{
"name": "event_add",
"parameters": {
"calendar_id": null,
"year": date.year,
"month": date.month,
"day": date.day,
// do nothing
}
else
{
}
*/
(async () => {
const widget = new _dali.widgets.event_edit.class_widget_event_edit(
(await get_available_calendars()),
{
"calendar_id": null,
"event_name": "",
"event_begin": lib_plankton.call.convey(
date,
[
x => ({
"timezone_shift": 0,
"date": date,
"time": {"hour": 12, "minute": 0, "second": 0}
}),
lib_plankton.pit.from_datetime,
x => lib_plankton.pit.shift_hour(x, 0),
lib_plankton.pit.to_datetime,
]
),
"event_end": lib_plankton.call.convey(
date,
[
x => ({
"timezone_shift": 0,
"date": date,
"time": {"hour": 12, "minute": 0, "second": 0}
}),
lib_plankton.pit.from_datetime,
x => lib_plankton.pit.shift_hour(x, +1),
lib_plankton.pit.to_datetime,
]
),
"event_location": null,
"event_link": null,
"event_description": null,
},
{
"read_only": false,
"action_cancel": () => {
_dali.overlay.toggle({"mode": false});
},
"action_add": (data) => {
_dali.model.event_add(
data.calendar_id,
{
"name": data.event_name,
"begin": data.event_begin,
"end": data.event_end,
"location": data.event_location,
"link": data.event_link,
"description": data.event_description,
}
)
.then(
() => {
update_entries();
_dali.overlay.toggle({"mode": false});
}
)
.catch(
(reason) => {
// todo
}
);
},
}
);
_dali.overlay.clear();
_dali.overlay.toggle({"mode": true});
await widget.load(_dali.overlay.get_content_element());
}) ();
},
}
)
);
await widget_weekview.load(target_element.querySelector("#overview-pane-right-weekview"));
}
_dali.model.listen_reset(
async (priviliged) => {
update_sources_and_entries(priviliged);
target_element.querySelector("#overview-hint").classList.toggle("overview-hint-hidden", priviliged);
}
);
}
return Promise.resolve<void>(undefined);
},

View file

@ -3,6 +3,90 @@
namespace _dali.backend
{
/**
*/
type type_conf = {
scheme : string;
host : string;
port : int;
path : string;
};
/**
*/
type type_request = {
method : lib_plankton.http.enum_method;
action : string;
input : (null | any);
};
/**
*/
type type_event_object = {
name : string;
begin : {
timezone_shift: int;
date: {
year: int;
month: int;
day: int;
};
time: (
null
|
{
hour: int;
minute: int;
second: int;
}
);
};
end : (
null
|
{
timezone_shift: int;
date: {
year: int;
month: int;
day: int;
};
time: (
null
|
{
hour: int;
minute: int;
second: int;
}
);
}
);
location : (
null
|
string
);
link : (
null
|
string
);
description : (
null
|
string
);
};
/**
*/
var _conf : type_conf;
/**
*/
var _data_chest : (
@ -14,44 +98,52 @@ namespace _dali.backend
/**
*/
function access_level_encode(
access_level : _dali.type.enum_access_level
) : ("none" | "view" | "edit" | "admin")
{
switch (access_level) {
case _dali.type.enum_access_level.none: return "none";
case _dali.type.enum_access_level.view: return "view";
case _dali.type.enum_access_level.edit: return "edit";
case _dali.type.enum_access_level.admin: return "admin";
}
}
var _cache : (
null
|
lib_plankton.cache.type_subject<boolean>
);
/**
*/
function access_level_decode(
access_level_encoded : ("none" | "view" | "edit" | "admin")
) : _dali.type.enum_access_level
var _queue : {
items : Array<
{
switch (access_level_encoded) {
case "none": return _dali.type.enum_access_level.none;
case "view": return _dali.type.enum_access_level.view;
case "edit": return _dali.type.enum_access_level.edit;
case "admin": return _dali.type.enum_access_level.admin;
}
request : type_request;
resolve : ((result : any) => void);
reject : ((reason : any) => void);
}
>;
busy : boolean;
};
/**
*/
export async function init(
) : Promise<void>
export async function initialize(
conf : type_conf
)
: Promise<void>
{
_conf = conf;
_data_chest = lib_plankton.storage.localstorage.implementation_chest(
{
"corner": "zeitbild",
}
);
_cache = lib_plankton.cache.make<boolean>(
/*
lib_plankton.storage.memory.implementation_chest(
{
}
)
*/
);
_queue = {
"items": [],
"busy": false,
};
return Promise.resolve<void>(undefined);
}
@ -59,7 +151,8 @@ namespace _dali.backend
/**
*/
async function get_session_key(
) : Promise<(null | string)>
)
: Promise<(null | string)>
{
try
{
@ -74,24 +167,23 @@ namespace _dali.backend
/**
*/
async function call(
method : lib_plankton.http.enum_method,
action : string,
input : (null | any)
) : Promise<any>
async function call_real(
request : type_request
)
: Promise<any>
{
const with_body : boolean = (
[
lib_plankton.http.enum_method.post,
lib_plankton.http.enum_method.put,
lib_plankton.http.enum_method.patch,
].includes(method)
].includes(request.method)
);
const session_key : (null | string) = await get_session_key();
const http_request : lib_plankton.http.type_request = {
"version": "HTTP/2",
"scheme": (
(_dali.conf.get()["backend"]["scheme"] === "http")
(_conf.scheme === "http")
?
"http"
:
@ -100,24 +192,24 @@ namespace _dali.backend
"host": lib_plankton.string.coin(
"{{host}}:{{port}}",
{
"host": _dali.conf.get()["backend"]["host"],
"port": _dali.conf.get()["backend"]["port"].toFixed(0),
"host": _conf.host,
"port": _conf.port.toFixed(0),
}
),
"path": lib_plankton.string.coin(
"{{base}}{{action}}",
{
"base": _dali.conf.get()["backend"]["path"],
"action": action,
"base": _conf.path,
"action": request.action,
}
),
"method": method,
"method": request.method,
"query": (
(with_body || (input === null))
(with_body || (request.input === null))
?
null
:
("?" + lib_plankton.www_form.encode(input))
("?" + lib_plankton.www_form.encode(request.input))
),
"headers": Object.assign(
{},
@ -137,11 +229,11 @@ namespace _dali.backend
)
),
"body": (
((! with_body) || (input === null))
((! with_body) || (request.input === null))
?
null
:
/*Buffer.from*/(lib_plankton.json.encode(input))
/*Buffer.from*/(lib_plankton.json.encode(request.input))
),
};
const http_response : lib_plankton.http.type_response = await lib_plankton.http.call(http_request);
@ -163,18 +255,94 @@ namespace _dali.backend
/**
*/
export async function is_logged_in(
) : Promise<boolean>
async function process(
)
: Promise<void>
{
if (_queue.busy)
{
// do nothing
}
else
{
_queue.busy = true;
while (_queue.items.length > 0)
{
const entry = _queue.items.shift();
let successful : boolean;
let reason : any;
let result : any;
try
{
result = await call_real(entry.request);
successful = true;
}
catch (error)
{
reason = error;
successful = false;
}
if (successful)
{
entry.resolve(result);
}
else
{
entry.reject(reason);
}
}
_queue.busy = false;
// process();
}
}
/**
*/
async function call(
method : lib_plankton.http.enum_method,
action : string,
input : (null | any)
)
: Promise<any>
{
const request : type_request = {
"method": method,
"action": action,
"input": input,
};
const promise : Promise<any> = new Promise<any>(
(resolve, reject) => {
_queue.items.push(
{
"request": request,
"resolve": resolve,
"reject": reject,
}
);
}
);
process();
return promise;
}
/**
*/
export function status(
)
: Promise<
{
// return ((await get_session_key()) !== null);
const result : {
logged_in : boolean;
} = await call(
name : (null | string);
}
>
{
return call(
lib_plankton.http.enum_method.get,
"/session/status",
null
);
return result.logged_in;
)
}
@ -182,7 +350,8 @@ namespace _dali.backend
*/
export async function session_prepare(
input : any
) : Promise<{kind : string; data : any;}>
)
: Promise<{kind : string; data : any;}>
{
return call(
lib_plankton.http.enum_method.post,
@ -196,7 +365,8 @@ namespace _dali.backend
*/
export function set_session_key(
session_key : string
) : Promise<void>
)
: Promise<void>
{
return (
_data_chest.write("session_key", session_key)
@ -209,7 +379,8 @@ namespace _dali.backend
export async function session_begin(
name : string,
password : string
) : Promise<void>
)
: Promise<void>
{
const session_key : string = await call(
lib_plankton.http.enum_method.post,
@ -227,7 +398,8 @@ namespace _dali.backend
/**
*/
export async function session_end(
) : Promise<void>
)
: Promise<void>
{
await call(
lib_plankton.http.enum_method.delete,
@ -242,7 +414,8 @@ namespace _dali.backend
/**
*/
export function user_list(
) : Promise<
)
: Promise<
Array<
{
id : int;
@ -262,7 +435,8 @@ namespace _dali.backend
/**
*/
export function user_dav_conf(
) : Promise<
)
: Promise<
(
null
|
@ -292,7 +466,8 @@ namespace _dali.backend
/**
*/
export function user_dav_token(
) : Promise<void>
)
: Promise<void>
{
return call(
lib_plankton.http.enum_method.patch,
@ -305,36 +480,22 @@ namespace _dali.backend
/**
*/
export async function calendar_list(
) : Promise<
)
: Promise<
Array<
{
id : int;
name : string;
hue : float;
access_level : _dali.type.enum_access_level;
access_level : string;
}
>
>
{
return (
call(
return call(
lib_plankton.http.enum_method.get,
"/calendar",
null
)
.then(
(entries) => Promise.resolve(
entries
.map(
(entry) => ({
"id": entry.id,
"name": entry.name,
"hue": entry.hue,
"access_level": access_level_decode(entry.access_level),
})
)
)
)
);
}
@ -342,13 +503,27 @@ namespace _dali.backend
/**
*/
export async function calendar_get(
calendar_id : _dali.type.calendar_id
) : Promise<
_dali.type.calendar_object
calendar_id : int
)
: Promise<
{
name : string;
hue : float;
access : {
public : boolean;
default_level : string;
attributed : Array<
{
user_id : int;
level : string;
}
>
};
resource_id : int;
}
>
{
return (
call(
return call(
lib_plankton.http.enum_method.get,
lib_plankton.string.coin(
"/calendar/{{calendar_id}}",
@ -357,43 +532,6 @@ namespace _dali.backend
}
),
null
)
.then(
(raw) => Promise.resolve(
{
"name": raw.name,
"hue": raw.hue,
"access": {
"public": raw.access.public,
"default_level": access_level_decode(raw.access.default_level),
"attributed": lib_plankton.map.hashmap.implementation_map(
lib_plankton.map.hashmap.make(
x => x.toFixed(0),
{
"pairs": (
raw.access.attributed
.map(
(entry) => ({
"key": entry.user_id,
"value": access_level_decode(entry.level),
})
)
),
}
)
),
},
// "resource_id": raw.resource_id
// TODO
"resource": {
"kind": "local",
"data": {
"events": []
}
},
}
)
)
);
}
@ -401,9 +539,38 @@ namespace _dali.backend
/**
*/
export async function calendar_add(
calendar_object : _dali.type.calendar_object
) : Promise<
_dali.type.calendar_id
data : {
name : string;
access : {
public : boolean;
default_level : string;
attributed : Array<
{
user_id : int;
level : string;
}
>;
};
resource : (
{
kind : "local";
data : {
};
}
|
{
kind : "ics_feed";
data : {
url : string;
from_fucked_up_wordpress : boolean;
};
}
);
hue : float;
}
)
: Promise<
int
>
{
return call(
@ -413,24 +580,7 @@ namespace _dali.backend
{
}
),
{
"name": calendar_object.name,
"hue": calendar_object.hue,
"access": {
"public": calendar_object.access.public,
"default_level": access_level_encode(calendar_object.access.default_level),
"attributed": (
lib_plankton.map.dump(calendar_object.access.attributed)
.map(
(pair) => ({
"user_id": pair.key,
"level": access_level_encode(pair.value),
})
)
)
},
"resource": calendar_object.resource,
}
data
);
}
@ -438,48 +588,35 @@ namespace _dali.backend
/**
*/
export async function calendar_change(
calendar_id : _dali.type.calendar_id,
id : int,
data : {
name : string;
hue : float;
access : {
public : boolean;
default_level : _dali.type.enum_access_level;
attributed : lib_plankton.map.type_map<
_dali.type.user_id,
_dali.type.enum_access_level
default_level : string;
attributed : Array<
{
user_id : int;
level : string;
}
>;
};
}
) : Promise<
)
: Promise<
void
>
{
return call(
lib_plankton.http.enum_method.put,
lib_plankton.string.coin(
"/calendar/{{calendar_id}}",
"/calendar/{{id}}",
{
"calendar_id": calendar_id.toFixed(0),
"id": id.toFixed(0),
}
),
{
"name": data.name,
"hue": data.hue,
"access": {
"public": data.access.public,
"default_level": access_level_encode(data.access.default_level),
"attributed": (
lib_plankton.map.dump(data.access.attributed)
.map(
(pair) => ({
"user_id": pair.key,
"level": access_level_encode(pair.value),
})
)
)
},
}
data
);
}
@ -487,17 +624,18 @@ namespace _dali.backend
/**
*/
export async function calendar_remove(
calendar_id : _dali.type.calendar_id
) : Promise<
id : int
)
: Promise<
void
>
{
return call(
lib_plankton.http.enum_method.delete,
lib_plankton.string.coin(
"/calendar/{{calendar_id}}",
"/calendar/{{id}}",
{
"calendar_id": calendar_id.toFixed(0),
"id": id.toFixed(0),
}
),
null
@ -508,9 +646,12 @@ namespace _dali.backend
/**
*/
export async function calendar_event_get(
calendar_id : _dali.type.calendar_id,
event_id : _dali.type.local_resource_event_id
) : Promise<_dali.type.event_object>
calendar_id : int,
event_id : int
)
: Promise<
type_event_object
>
{
return call(
lib_plankton.http.enum_method.get,
@ -529,9 +670,15 @@ namespace _dali.backend
/**
*/
export async function calendar_event_add(
calendar_id : _dali.type.calendar_id,
event_object : _dali.type.event_object
) : Promise<void>
calendar_id : int,
event_data : type_event_object
)
: Promise<
{
local_resource_event_id : (null | int);
hash : string;
}
>
{
return call(
lib_plankton.http.enum_method.post,
@ -541,18 +688,20 @@ namespace _dali.backend
"calendar_id": calendar_id.toFixed(0),
}
),
event_object
event_data
);
}
/**
* @todo Möglichkeit den Kalender zu ändern
*/
export async function calendar_event_change(
calendar_id : _dali.type.calendar_id,
event_id : _dali.type.local_resource_event_id,
event_object : _dali.type.event_object
) : Promise<void>
calendar_id : int,
event_id : int,
event_object : type_event_object
)
: Promise<void>
{
return call(
lib_plankton.http.enum_method.put,
@ -571,9 +720,10 @@ namespace _dali.backend
/**
*/
export async function calendar_event_remove(
calendar_id : _dali.type.calendar_id,
event_id : _dali.type.local_resource_event_id
) : Promise<void>
calendar_id : int,
event_id : int
)
: Promise<void>
{
return call(
lib_plankton.http.enum_method.delete,
@ -593,62 +743,47 @@ namespace _dali.backend
* @todo prevent loops
*/
export async function events(
from_pit : lib_plankton.pit.type_pit,
to_pit : lib_plankton.pit.type_pit,
options : {
calendar_ids ?: (null | Array<_dali.type.calendar_id>);
} = {}
) : Promise<
from_timestamp : int,
to_timestamp : int,
{
"calendar_ids": calendar_ids = null,
}
:
{
calendar_ids ?: (null | Array<int>);
}
=
{
}
)
: Promise<
Array<
{
calendar_id : _dali.type.calendar_id;
hash : string;
calendar_id : int;
calendar_name : string;
hue : float;
access_level : _dali.type.enum_access_level;
event_id : (null | _dali.type.local_resource_event_id);
event_object : _dali.type.event_object;
access_level : string;
event_id : (null | int);
event_object : type_event_object;
}
>
>
{
options = Object.assign(
{
"calendar_ids": null,
},
options
);
return (
call(
return call(
lib_plankton.http.enum_method.get,
"/events",
Object.assign(
{
"from": from_pit,
"to": to_pit,
"from": from_timestamp,
"to": to_timestamp,
},
(
(options.calendar_ids === null)
(calendar_ids === null)
?
{}
:
{"calendar_ids": options.calendar_ids.join(",")}
)
)
)
.then(
(data) => Promise.resolve(
data
.map(
(entry) => ({
"calendar_id": entry.calendar_id,
"calendar_name": entry.calendar_name,
"hue": entry.hue,
"access_level": access_level_decode(entry.access_level),
"event_id": entry.event_id,
"event_object": entry.event_object,
})
)
{"calendar_ids": calendar_ids.join(",")}
)
)
);

View file

@ -5,21 +5,54 @@
html
{
background-color: hsl(0, 0%, 12.5%);
color: hsl(0, 0%, 100%);
background-color: hsl(var(--hue), 0%, 12.5%);
color: hsl(var(--hue), 0%, 100%);
font-family: sans-serif;
}
header
{
background-color: hsl(0, 0%, 25%);
/*
background-color: hsl(0, 0%, 25%);
border-bottom: 2px solid #888;
padding-bottom: 16px;
*/
margin-bottom: 16px;
}
#overlay
{
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: hsla(var(--hue), 0%, 0%, 0.75);
z-index: 2;
}
#overlay_content
{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
padding: 32px;
background-color: hsl(0, 0%, 12.5%);
color: hsl(0, 0%, 100%);
}
#overlay:not(.overlay_active)
{
display: none;
}
nav > ul
{
list-style-type: none;
@ -56,12 +89,14 @@ nav a:hover
a
{
text-decoration: none;
color: hsl(var(--hue), 50%, 50%);
color: hsl(var(--hue), 0%, 87.5%);
}
a:hover
{
color: hsl(var(--hue), 50%, 75%);
color: hsl(var(--hue), 0%, 100%);
border-bottom: 2px solid hsl(0, 0%, 100%);
transition: 1s ease color;
}
input,select,textarea
@ -74,13 +109,19 @@ button
padding: 8px;
text-transform: uppercase;
cursor: pointer;
background-color: hsl(var(--hue), 0%, 6.125%);
border: 1px solid hsl(var(--hue), 0%, 6.125%);
color: hsl(0, 0%, 87.5%);
margin: 4px;
border-radius: 4px;
}
input,select,textarea,button
input,select,textarea
{
background-color: hsl(0, 0%, 0%);
background-color: hsl(0, 0%, 25%);
border: 1px solid hsl(0, 0%, 25%);
color: hsl(0, 0%, 100%);
border: 1px solid hsl(0, 0%, 75%);
margin: 4px;
border-radius: 2px;
border-radius: 4px;
}

View file

@ -1,13 +0,0 @@
#calendar_add .plankton_input_group_field[rel="attributed"] > .plankton_input_list > .plankton_input_list_elements > .plankton_input_list_element
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
#calendar_add .plankton_input_group_field[rel="attributed"] > .plankton_input_list > .plankton_input_list_elements > .plankton_input_list_element > .plankton_input_list_element_input > .plankton_input_group
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

View file

@ -1,8 +0,0 @@
#event_add .plankton_input_group_field[rel="begin"] > .plankton_input_group
,
#event_add .plankton_input_group_field[rel="end"] > .plankton_input_soft_container > .plankton_input_soft_core_wrapper > .plankton_input_group
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

View file

@ -1,8 +0,0 @@
#event_edit .plankton_input_group_field[rel="begin"] > .plankton_input_group
,
#event_edit .plankton_input_group_field[rel="end"] > .plankton_input_soft_container > .plankton_input_soft_core_wrapper > .plankton_input_group
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}

View file

@ -11,6 +11,11 @@
font-weight: bold;
}
#overview-hint.overview-hint-hidden
{
display: none;
}
#overview-body
{
display: flex;

View file

@ -1,26 +1,33 @@
.plankton_input_group_field {
.plankton_input_group_field
{
margin-bottom: 8px;
}
.plankton_input_group_field_label {
.plankton_input_group_field_label
{
display: block;
font-weight: bold;
font-size: 0.8em;
text-transform: uppercase;
}
.plankton_input_soft_container > * {
.plankton_input_soft_container > *
{
display: inline-block;
}
.plankton_input_soft_setter {
.plankton_input_soft_setter
{
margin-right: 8px;
}
.plankton_input_soft_inactive {
.plankton_input_soft_inactive
{
display: none !important;
}
.plankton_input_group {
.plankton_input_group
{
margin-left: 24px;
}
@ -44,3 +51,8 @@
{
vertical-align: top;
}
.plankton_input_password_exhibit
{
display: none;
}

View file

@ -0,0 +1,75 @@
.widget-menu
{
margin-left: auto;
margin-right: 8px;
width: fit-content;
}
.widget-menu.widget-menu-collapsed > .widget-menu-platform
{
display: none;
}
.widget-menu-button
{
text-transform: initial;
}
.widget-menu-entry
{
cursor: pointer;
}
.widget-menu-platform
{
background-color: hsl(var(--hue), 0%, 25%);
border-radius: 2px;
border: 1px solid hsl(var(--hue), 0%, 0%);
padding: 8px;
min-width: 200px;
}
.widget-menu-platform:not(.widget-menu-platform-collapsed)
{
position: fixed;
top: 32px;
right: 32px;
z-index: 2;
}
.widget-menu-entries
{
padding: 0;
margin: 0;
list-style-type: none;
}
.widget-menu-entry
{
margin: 12px 16px;
padding: 8px;
text-transform: capitalize;
}
.widget-menu-entry:not(:hover)
{
background-color: hsl(var(--hue), 0%, 25%);
color: hsl(var(--hue), 0%, 100%);
}
.widget-menu-entry:hover::after
{
content: " «";
/*
background-color: hsl(var(--hue), 0%, 50%);
color: hsl(var(--hue), 0%, 100%);
*/
}
.widget-menu-entry.widget-menu-entry-hidden
{
display: none;
}

View file

@ -1,9 +1,23 @@
.sources
{
font-size: 0.75em;
}
.sources:not(.sources-priviliged) > .sources-create
{
display: none;
}
.sources-create
{
margin-left: 8px;
}
.sources-entries
{
margin: 0;
padding: 0;
list-style-type: none;
font-size: 0.75em;
}
.sources-entry

245
source/types.ts Normal file
View file

@ -0,0 +1,245 @@
/**
*/
namespace _dali
{
/**
*/
export enum enum_access_level {
none,
view,
edit,
admin
}
/**
*/
export type type_user_id = int;
/**
*/
export type type_user_object = {
name : string;
email_address : (
null
|
string
);
};
/**
* @todo deprecate?
*/
export type type_local_resource_event_id = int;
/**
* info: das ist nicht deckungsgleich mit der Event-ID aus dem Backend; hiermit werden sowohl lokale als auch
* extern eingebundene Events kodiert
*
* @example "local:1234"
* @example "ics~2345"
*/
export type type_event_key = string;
/**
*/
export type type_event_object = {
name : string;
begin : lib_plankton.pit.type_datetime;
end : (
null
|
lib_plankton.pit.type_datetime
);
location : (
null
|
string
);
link : (
null
|
string
);
description : (
null
|
string
);
};
/**
*/
export type type_event_entry = {
id : (null | type_local_resource_event_id);
key : type_event_key;
object : type_event_object;
};
/**
*/
export type type_event_object_extended = {
key : type_event_key;
calendar_id : type_calendar_id;
calendar_name : string;
hue : float;
access_level : enum_access_level;
event_id : (null | type_local_resource_event_id);
event_object : type_event_object;
};
/**
*/
export type type_resource_id = int;
/**
*/
export type type_resource_object = (
{
kind : "local";
data : {
events : Array<
type_event_object
>;
};
}
|
{
kind : "caldav";
data : {
read_only : boolean;
url : string;
};
}
);
/**
*/
export type type_calendar_id = int;
/**
*/
export type type_calendar_object = {
name : string;
hue : float;
access : {
public : boolean;
default_level : enum_access_level;
attributed : lib_plankton.map.type_map<
type_user_id,
enum_access_level
>;
};
resource_id : type_resource_id;
};
/**
*/
export type type_calendar_object_reduced = {
name : string;
hue : float;
access_level : enum_access_level;
};
/**
*/
export type type_calendar_object_reduced_with_id = {
id : type_calendar_id;
name : string;
hue : float;
access_level : enum_access_level;
};
/**
*/
export enum enum_view_mode
{
week,
list,
}
/**
*/
export function access_level_encode(
access_level : _dali.enum_access_level
) : ("none" | "view" | "edit" | "admin")
{
switch (access_level)
{
case _dali.enum_access_level.none: return "none";
case _dali.enum_access_level.view: return "view";
case _dali.enum_access_level.edit: return "edit";
case _dali.enum_access_level.admin: return "admin";
}
}
/**
*/
export function access_level_decode(
representation : /*("none" | "view" | "edit" | "admin")*/string
) : _dali.enum_access_level
{
switch (representation)
{
case "none": return _dali.enum_access_level.none;
case "view": return _dali.enum_access_level.view;
case "edit": return _dali.enum_access_level.edit;
case "admin": return _dali.enum_access_level.admin;
default: throw (new Error("invalid access level representation: " + representation));
}
}
/**
*/
export function view_mode_encode(
mode : _dali.enum_view_mode
) : string
{
switch (mode)
{
case _dali.enum_view_mode.week: {return "week"; break;}
case _dali.enum_view_mode.list: {return "list"; break;}
default: {throw (new Error("invalid mode"));}
}
}
/**
*/
export function view_mode_decode(
view_mode_encoded : string
) : _dali.enum_view_mode
{
const map : Record<string, _dali.enum_view_mode> = {
"week": _dali.enum_view_mode.week,
"list": _dali.enum_view_mode.list,
};
if (! (view_mode_encoded in map))
{
throw (new Error("invalid mode: " + view_mode_encoded));
}
else
{
return map[view_mode_encoded];
}
}
}

View file

@ -0,0 +1,242 @@
namespace _dali.widgets.calendar_edit
{
/**
*/
export class class_widget_calendar_edit
implements lib_plankton.zoo_widget.interface_widget
{
/**
*/
private users : Array<{id : _dali.type_user_id; name : string;}>;
/**
*/
private read_only : boolean;
/**
*/
private action_cancel ?: (null | (() => void));
/**
*/
private action_add ?: (null | ((value : _dali.type_calendar_object) => void));
/**
*/
private action_change ?: (null | ((value : _dali.type_calendar_object) => void));
/**
*/
private action_remove ?: (null | ((value : _dali.type_calendar_object) => void));
/**
*/
private initial_value : (null | _dali.type_calendar_object);
/**
*/
public constructor(
users : Array<{id : _dali.type_user_id; name : string;}>,
{
"read_only": read_only = false,
"action_cancel": action_cancel = null,
"action_add": action_add = null,
"action_change": action_change = null,
"action_remove": action_remove = null,
"initial_value": initial_value = null,
}
:
{
read_only ?: boolean;
action_cancel ?: (null | (() => void));
action_add ?: (null | ((value : _dali.type_calendar_object) => void))
action_change ?: (null | ((value : _dali.type_calendar_object) => void));
action_remove ?: (null | ((value : _dali.type_calendar_object) => void));
initial_value ?: (null | _dali.type_calendar_object);
}
=
{
}
)
{
this.users = users;
this.read_only = read_only;
this.action_cancel = action_cancel;
this.action_add = action_add;
this.action_change = action_change;
this.action_remove = action_remove;
this.initial_value = initial_value;
}
/**
* [implementation]
*/
public async load(
target_element : HTMLElement
) : Promise<void>
{
const form : lib_plankton.zoo_form.class_form<
_dali.type_calendar_object,
_dali.type_calendar_object
> = new lib_plankton.zoo_form.class_form<
_dali.type_calendar_object,
_dali.type_calendar_object
>(
(value) => value,
(raw) => raw,
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("calendar.name")
},
{
"name": "hue",
"input": new lib_plankton.zoo_input.class_input_hue(
),
"label": lib_plankton.translate.get("calendar.hue"),
},
{
"name": "access",
"input": new lib_plankton.zoo_input.class_input_group(
[
{
"name": "public",
"input": new lib_plankton.zoo_input.class_input_checkbox(),
"label": lib_plankton.translate.get("calendar.access.public"),
},
{
"name": "default_level",
"input": _dali.helpers.input_access_level(),
"label": lib_plankton.translate.get("calendar.access.default_level"),
},
{
"name": "attributed",
"input": _dali.helpers.input_attributed_access(this.users),
"label": lib_plankton.translate.get("calendar.access.attributed"),
},
]
),
"label": lib_plankton.translate.get("calendar.access.access"),
},
{
"name": "resource",
"input": new lib_plankton.zoo_input.class_input_hidden(
),
"label": lib_plankton.translate.get("calendar.resource"),
},
]
),
(
[]
// add
.concat(
((! this.read_only) && (! (this.action_add === null)))
?
[
{
"label": lib_plankton.translate.get("widget.calendar_edit.actions.add"),
"procedure": async (get_value, get_representation) => {
const value : _dali.type_calendar_object = await get_value();
this.action_add(value);
}
},
]
:
[]
)
// change
.concat(
((! this.read_only) && (! (this.action_change === null)))
?
[
{
"label": lib_plankton.translate.get("widget.calendar_edit.actions.change"),
"procedure": async (get_value, get_representation) => {
const value : _dali.type_calendar_object = await get_value();
this.action_change(value);
}
},
]
:
[]
)
// remove
.concat(
((! this.read_only) && (! (this.action_change === null)))
?
[
{
"label": lib_plankton.translate.get("widget.calendar_edit.actions.remove"),
"procedure": async (get_value, get_representation) => {
const value : _dali.type_calendar_object = await get_value();
this.action_remove(value);
}
},
]
:
[]
)
// cancel
.concat(
(! (this.action_cancel === null))
?
[
{
"label": lib_plankton.translate.get("common.cancel"),
"procedure": async () => {
this.action_cancel();
}
},
]
:
[]
)
)
);
await form.setup(target_element);
await form.input_write(
(! (this.initial_value === null))
?
this.initial_value
:
{
"name": "",
"hue": lib_plankton.random.generate_unit(),
"access": {
"public": false,
"default_level": _dali.enum_access_level.view,
"attributed": lib_plankton.map.hashmap.implementation_map<
_dali.type_user_id,
_dali.enum_access_level
>(
lib_plankton.map.hashmap.make<
_dali.type_user_id,
_dali.enum_access_level
>(
user_id => user_id.toFixed(0),
)
),
},
/**
* @todo
*/
"resource_id": 0,
}
);
}
}
}

View file

@ -0,0 +1,296 @@
namespace _dali.widgets.event_edit
{
/**
*/
export type type_value = {
calendar_id : (null | _dali.type_calendar_id);
event_name : string;
event_begin : lib_plankton.pit.type_datetime;
event_end : (null | lib_plankton.pit.type_datetime);
event_location : (null | string);
event_link : (null | string);
event_description : (null | string);
};
/**
*/
export type type_representation = {
calendar_id : string;
event_name : string;
event_begin : lib_plankton.pit.type_datetime;
event_end : (null | lib_plankton.pit.type_datetime);
event_location : (null | string);
event_link : (null | string);
event_description : (null | string);
};
/**
*/
export class class_widget_event_edit
implements lib_plankton.zoo_widget.interface_widget
{
/**
* [data]
*/
private available_calendars : Array<
{
id : int;
name : string;
hue : float;
access_level : _dali.enum_access_level;
}
>;
/**
* [data]
*/
private read_only : boolean;
/**
* [data]
*/
private initial_value : type_value;
/**
* [hook]
*/
private action_cancel ?: (null | (() => void));
/**
* [hook]
*/
private action_add ?: (null | ((value : type_value) => void));
/**
* [hook]
*/
private action_change ?: (null | ((value : type_value) => void));
/**
* [hook]
*/
private action_remove ?: (null | ((value : type_value) => void));
/**
*/
public constructor(
available_calendars : Array<
{
id : int;
name : string;
hue : float;
access_level : _dali.enum_access_level;
}
>,
initial_value : type_value,
{
"read_only": read_only = false,
"action_cancel": action_cancel = null,
"action_add": action_add = null,
"action_change": action_change = null,
"action_remove": action_remove = null,
}
:
{
read_only ?: boolean;
action_cancel ?: (null | (() => void));
action_add ?: (null | ((value : type_value) => void));
action_change ?: (null | ((value : type_value) => void));
action_remove ?: (null | ((value : type_value) => void));
}
=
{
}
)
{
// data
this.read_only = read_only;
this.available_calendars = available_calendars;
this.initial_value = initial_value;
// hooks
this.action_cancel = action_cancel;
this.action_add = action_add;
this.action_change = action_change;
this.action_remove = action_remove;
}
/**
* [implementation]
*/
public async load(
target_element : HTMLElement
) : Promise<void>
{
const form : lib_plankton.zoo_form.class_form<
type_value,
type_representation
> = new lib_plankton.zoo_form.class_form<
type_value,
type_representation
>(
(value) => ({
"calendar_id": (value.calendar_id ?? this.available_calendars[0].id).toFixed(0),
"event_name": value.event_name,
"event_begin": value.event_begin,
"event_end": value.event_end,
"event_location": value.event_location,
"event_link": value.event_link,
"event_description": value.event_description,
}),
(representation) => ({
"calendar_id": parseInt(representation.calendar_id),
"event_name": representation.event_name,
"event_begin": representation.event_begin,
"event_end": representation.event_end,
"event_location": representation.event_location,
"event_link": representation.event_link,
"event_description": representation.event_description,
}),
new lib_plankton.zoo_input.class_input_group<any>(
[
{
"name": "calendar_id",
"input": new lib_plankton.zoo_input.class_input_selection(
(
this.available_calendars
.map(
(entry) => ({
"value": entry.id.toFixed(0),
"label": entry.name,
})
)
)
),
"label": lib_plankton.translate.get("calendar.calendar")
},
{
"name": "event_name",
"input": new lib_plankton.zoo_input.class_input_text(
),
"label": lib_plankton.translate.get("event.name")
},
{
"name": "event_begin",
"input": _dali.helpers.datetime_input(),
"label": lib_plankton.translate.get("event.begin")
},
{
"name": "event_end",
"input": new lib_plankton.zoo_input.class_input_soft<lib_plankton.pit.type_datetime>(
_dali.helpers.datetime_input()
),
"label": lib_plankton.translate.get("event.end")
},
{
"name": "event_location",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.location")
},
{
"name": "event_link",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_text(
)
),
"label": lib_plankton.translate.get("event.link")
},
{
"name": "event_description",
"input": new lib_plankton.zoo_input.class_input_soft<string>(
new lib_plankton.zoo_input.class_input_textarea(
)
),
"label": lib_plankton.translate.get("event.description")
},
]
),
(
[]
// add
.concat(
((! this.read_only) && (! (this.action_add === null)))
?
[
{
"label": lib_plankton.translate.get("widget.event_edit.actions.add"),
"procedure": async (get_value, get_representation) => {
const value : type_value = await get_value();
this.action_add(value);
}
},
]
:
[]
)
// change
.concat(
((! this.read_only) && (! (this.action_change === null)))
?
[
{
"label": lib_plankton.translate.get("widget.event_edit.actions.change"),
"procedure": async (get_value, get_representation) => {
const value : type_value = await get_value();
this.action_change(value);
}
},
]
:
[]
)
// remove
.concat(
((! this.read_only) && (! (this.action_change === null)))
?
[
{
"label": lib_plankton.translate.get("widget.event_edit.actions.remove"),
"procedure": async (get_value, get_representation) => {
const value : type_value = await get_value();
this.action_remove(value);
}
},
]
:
[]
)
// cancel
.concat(
(! (this.action_cancel === null))
?
[
{
"label": lib_plankton.translate.get("common.cancel"),
"procedure": async () => {
this.action_cancel();
}
},
]
:
[]
)
)
);
await form.setup(target_element);
await form.input_write(this.initial_value);
}
}
}

View file

@ -4,12 +4,12 @@ namespace _dali.widgets.listview
/**
*/
type type_entry = {
calendar_id : _dali.type.calendar_id;
calendar_id : _dali.type_calendar_id;
calendar_name : string;
hue : float;
access_level : _dali.type.enum_access_level;
event_id : (null | _dali.type.local_resource_event_id);
event_object : _dali.type.event_object;
access_level : _dali.enum_access_level;
event_id : (null | _dali.type_local_resource_event_id);
event_object : _dali.type_event_object;
};
@ -19,7 +19,7 @@ namespace _dali.widgets.listview
(
from_pit : lib_plankton.pit.type_pit,
to_pit : lib_plankton.pit.type_pit,
calendar_ids : Array<_dali.type.calendar_id>
calendar_ids : Array<_dali.type_calendar_id>
)
=>
Promise<Array<type_entry>>
@ -28,7 +28,7 @@ namespace _dali.widgets.listview
/**
*/
export class class_widget_listview extends _dali.class_widget
export class class_widget_listview implements lib_plankton.zoo_widget.interface_widget
{
/**
@ -45,9 +45,9 @@ namespace _dali.widgets.listview
*/
private action_select_event : (
(
calendar_id : _dali.type.calendar_id,
access_level : _dali.type.enum_access_level,
event_id : _dali.type.local_resource_event_id
calendar_id : _dali.type_calendar_id,
access_level : _dali.enum_access_level,
event_id : _dali.type_local_resource_event_id
)
=>
void
@ -71,9 +71,9 @@ namespace _dali.widgets.listview
options : {
action_select_event ?: (
(
calendar_id : _dali.type.calendar_id,
access_level : _dali.type.enum_access_level,
event_id : _dali.type.local_resource_event_id
calendar_id : _dali.type_calendar_id,
access_level : _dali.enum_access_level,
event_id : _dali.type_local_resource_event_id
)
=>
void
@ -94,7 +94,6 @@ namespace _dali.widgets.listview
},
options
);
super();
this.get_entries = get_entries;
this.container = null;
this.action_select_event = options.action_select_event;
@ -105,14 +104,14 @@ namespace _dali.widgets.listview
/**
*/
public toggle_visibility(
calendar_id : _dali.type.calendar_id
calendar_id : _dali.type_calendar_id
) : void
{
this.container.querySelectorAll(".listview-entry").forEach(
(element) => {
const rel : string = element.getAttribute("rel");
const parts : Array<string> = rel.split("/");
const calendar_id_ : _dali.type.calendar_id = parseInt(parts[0]);
const calendar_id_ : _dali.type_calendar_id = parseInt(parts[0]);
if (! (calendar_id === calendar_id_)) {
// do nothing
}
@ -156,7 +155,7 @@ namespace _dali.widgets.listview
"add_href": "",
"add_label": lib_plankton.translate.get("widget.listview.add"),
"add_extra_classes": (
(! await _dali.backend.is_logged_in())
(! await _dali.is_logged_in())
?
" listview-add-hidden"
:
@ -251,10 +250,10 @@ namespace _dali.widgets.listview
),
"access_level": (() => {
switch (entry.access_level) {
case _dali.type.enum_access_level.none: return "none";
case _dali.type.enum_access_level.view: return "view";
case _dali.type.enum_access_level.edit: return "edit";
case _dali.type.enum_access_level.admin: return "admin";
case _dali.enum_access_level.none: return "none";
case _dali.enum_access_level.view: return "view";
case _dali.enum_access_level.edit: return "edit";
case _dali.enum_access_level.admin: return "admin";
}
}) (),
}
@ -290,20 +289,20 @@ namespace _dali.widgets.listview
else {
const rel : string = element.getAttribute("rel");
const parts : Array<string> = rel.split("/");
const calendar_id : _dali.type.calendar_id = parseInt(parts[0]);
const event_id : (null | _dali.type.local_resource_event_id) = (
const calendar_id : _dali.type_calendar_id = parseInt(parts[0]);
const event_id : (null | _dali.type_local_resource_event_id) = (
parts[1] === "-"
?
null
:
parseInt(parts[1])
);
const access_level : _dali.type.enum_access_level = (() => {
const access_level : _dali.enum_access_level = (() => {
switch (parts[2]) {
case "none": return _dali.type.enum_access_level.none;
case "view": return _dali.type.enum_access_level.view;
case "edit": return _dali.type.enum_access_level.edit;
case "admin": return _dali.type.enum_access_level.admin;
case "none": return _dali.enum_access_level.none;
case "view": return _dali.enum_access_level.view;
case "edit": return _dali.enum_access_level.edit;
case "admin": return _dali.enum_access_level.admin;
}
}) ();
this.action_select_event(

View file

@ -0,0 +1,195 @@
namespace _dali.widgets.login
{
/**
*/
export class class_widget_login implements lib_plankton.zoo_widget.interface_widget
{
/**
* [data]
*/
private initial_name : string;
/**
* [hook]
*/
private action_cancel : (null | (() => void));
/**
* [hook]
*/
private action_success : (null | (() => void));
/**
*/
public constructor(
{
"initial_name": initial_name = "",
"action_cancel": action_cancel = null,
"action_success": action_success = null,
}
:
{
initial_name ?: string;
action_cancel ?: (null | (() => void));
action_success ?: (null | (() => void));
}
=
{
}
)
{
this.initial_name = initial_name;
this.action_cancel = action_cancel;
this.action_success = action_success;
}
/**
* [implementation]
*/
public async load(
target_element : Element
)
: Promise<void>
{
const preparation : {kind : string; data : any;} = await _dali.backend.session_prepare(
{
"oidc_redirect_uri_template": _dali.conf.get()["misc"]["oidc_redirect_uri_template"],
}
);
switch (preparation.kind)
{
case "internal":
{
target_element.innerHTML = await _dali.helpers.template_coin(
"widget-login",
"default",
{
}
);
const form : lib_plankton.zoo_form.class_form<
{name : string; password : string;},
{name : string; password : string;}
> = new lib_plankton.zoo_form.class_form<
{name : string; password : string;},
{name : string; password : string;}
>(
x => x,
x => x,
new lib_plankton.zoo_input.class_input_group<
{name : string; password : string;}
>(
[
{
"name": "name",
"input": new lib_plankton.zoo_input.class_input_text(),
"label": lib_plankton.translate.get("widget.login.internal.name"),
},
{
"name": "password",
"input": new lib_plankton.zoo_input.class_input_password(),
"label": lib_plankton.translate.get("widget.login.internal.password"),
},
]
),
(
[]
.concat(
[
{
"label": lib_plankton.translate.get("widget.login.internal.do"),
"procedure": async (get_value, get_representation) => {
const value : any = await get_value();
try
{
await _dali.backend.session_begin(
value.name,
value.password
);
if (this.action_success !== null) this.action_success();
}
catch (error)
{
// todo
}
}
}
]
)
.concat(
(this.action_cancel === null)
?
[]
:
[
{
"label": lib_plankton.translate.get("common.cancel"),
"procedure": () => {
this.action_cancel();
}
}
]
)
)
);
await form.setup(document.querySelector(".widget-login"));
await form.input_write(
{
"name": this.initial_name,
"password": "",
}
);
break;
}
case "oidc":
{
// link
{
let element_a : HTMLElement = document.createElement("a");;
element_a.textContent = lib_plankton.string.coin(
lib_plankton.translate.get("widget.login.oidc.via"),
{
"title": preparation.data.label,
}
);
element_a.setAttribute("href", preparation.data.url);
target_element.appendChild(element_a);
}
{
let dom_br : HTMLElement = document.createElement("br");
target_element.appendChild(dom_br);
}
{
let dom_br : HTMLElement = document.createElement("br");
target_element.appendChild(dom_br);
}
// cancel
{
let dom_cancel : HTMLElement = document.createElement("button");
dom_cancel.textContent = lib_plankton.translate.get("common.cancel");
dom_cancel.addEventListener(
"click",
() => {
this.action_cancel();
}
);
target_element.appendChild(dom_cancel);
}
break;
}
default:
{
// todo
break;
}
}
}
}
}

View file

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

View file

@ -0,0 +1,190 @@
namespace _dali.widgets.menu
{
/**
*/
type type_entry_data = {
label : string;
groups : Array<string>;
action : (() => void);
}
/**
*/
export class class_widget_menu implements lib_plankton.zoo_widget.interface_widget
{
/**
*/
private entries : Array<
{
data : type_entry_data;
element : (null | HTMLElement);
}
>;
/**
*/
private initial_groups : Array<string>;
/**
*/
private label : (null | string);
/**
*/
private container : (null | HTMLElement);
/**
*/
public constructor(
entry_data_list : Array<type_entry_data>,
{
"initial_groups": initial_groups = [],
"initial_label": initial_label = "=",
}
:
{
initial_groups ?: Array<string>;
initial_label ?: string;
}
=
{
}
)
{
this.entries = entry_data_list.map(
entry_data => (
{
"data": entry_data,
"element": null,
}
)
);
this.initial_groups = initial_groups;
this.label = initial_label;
this.container = null;
}
/**
*/
public set_groups(
groups : Array<string>
)
: void
{
this.entries.forEach(
entry => {
const active : boolean = groups.some(group => entry.data.groups.includes(group));
entry.element.classList.toggle("widget-menu-entry-hidden", (! active));
}
);
}
/**
*/
public set_label(
label ?: string
)
: void
{
this.label = label;
this.container.querySelector(".widget-menu-button").textContent = (
(this.label === null)
?
"[=]"
:
("[" + this.label + "]")
);
}
/**
*/
private toggle_collapsed(
{
"mode": mode = null,
}
:
{
mode ?: (null | boolean);
}
=
{
}
)
: void
{
this.container.classList.toggle("widget-menu-collapsed", mode ?? undefined);
}
/**
* [implementation]
*/
public async load(
target_element : Element
)
: Promise<void>
{
// container
{
const dom_container : HTMLElement = document.createElement("div");
dom_container.classList.add("widget-menu");
// button
{
const dom_button : HTMLElement = document.createElement("button");
dom_button.textContent = "[" + this.label + "]";
dom_button.classList.add("widget-menu-button");
dom_button.addEventListener(
"click",
() => {
this.toggle_collapsed();
}
);
dom_container.classList.toggle("widget-menu-collapsed", true);
dom_container.appendChild(dom_button);
}
// platform
{
const dom_platform : HTMLElement = document.createElement("div");
dom_platform.classList.add("widget-menu-platform");
{
const dom_list : HTMLElement = document.createElement("ul");
dom_list.classList.add("widget-menu-entries");
this.entries.forEach(
entry => {
const dom_entry : HTMLElement = document.createElement("li");
dom_entry.classList.add("widget-menu-entry");
dom_entry.textContent = entry.data.label;
dom_entry.addEventListener(
"click",
() => {
this.toggle_collapsed({"mode": true});
entry.data.action();
}
);
dom_list.appendChild(dom_entry);
entry.element = dom_entry;
}
);
dom_platform.appendChild(dom_list);
}
dom_container.appendChild(dom_platform);
}
target_element.appendChild(dom_container);
this.container = dom_container;
}
this.set_groups(this.initial_groups);
}
}
}

View file

@ -4,14 +4,14 @@ namespace _dali.widgets.mode_switcher
/**
*/
type type_option = {
mode : _dali.type.enum_view_mode;
mode : _dali.enum_view_mode;
label : string,
};
/**
*/
export class class_widget_mode_switcher extends _dali.class_widget
export class class_widget_mode_switcher implements lib_plankton.zoo_widget.interface_widget
{
/**
@ -21,12 +21,12 @@ namespace _dali.widgets.mode_switcher
/**
*/
private initial_selection : (null | _dali.type.enum_view_mode);
private initial_selection : (null | _dali.enum_view_mode);
/**
*/
private action_change : (null | ((mode : _dali.type.enum_view_mode) => void));
private action_change : (null | ((mode : _dali.enum_view_mode) => void));
/**
@ -39,15 +39,14 @@ namespace _dali.widgets.mode_switcher
}
:
{
initial_selection ?: (null | _dali.type.enum_view_mode),
action_change ?: (null | ((mode : _dali.type.enum_view_mode) => void))
initial_selection ?: (null | _dali.enum_view_mode),
action_change ?: (null | ((mode : _dali.enum_view_mode) => void))
}
=
{
}
)
{
super();
this.options = options;
this.initial_selection = initial_selection;
this.action_change = action_change;
@ -100,7 +99,7 @@ namespace _dali.widgets.mode_switcher
target_element.querySelectorAll(".widget-mode_switcher-option").forEach(
element => {
const view_mode_encoded : string = element.getAttribute("rel");
const mode : _dali.type.enum_view_mode = _dali.view_mode_decode(view_mode_encoded);
const mode : _dali.enum_view_mode = _dali.view_mode_decode(view_mode_encoded);
element.querySelector("input").addEventListener(
"change",
(event) => {

View file

@ -4,93 +4,171 @@ namespace _dali.widgets.sources
/**
*/
type type_entry = {
id : _dali.type.calendar_id;
id : _dali.type_calendar_id;
name : string;
hue : float;
access_level : _dali.type.enum_access_level;
access_level : _dali.enum_access_level;
};
/**
*/
export class class_widget_sources extends _dali.class_widget
export class class_widget_sources implements lib_plankton.zoo_widget.interface_widget
{
/**
* [dependency]
*/
private keys : Array<string>;
/**
*/
private data : Record<string, type_entry>;
private get_entries : (() => Promise<Array<type_entry>>);
/**
* [hook]
*/
private action_open : ((entry : type_entry) => void);
/**
* [hook]
*/
private action_toggle_visibility : ((entry : type_entry) => void);
/**
* [hook]
*/
private action_create : (() => void);
/**
*/
private priviliged : boolean;
/**
* [state]
*/
private container : (null | Element);
/**
*/
public constructor(
entries : Array<type_entry>,
options : {
get_entries : (() => Promise<Array<type_entry>>),
{
"action_open": action_open = ((calendar_id) => {}),
"action_toggle_visibility": action_toggle_visibility = ((calendar_id) => {}),
"action_create": action_create = (() => {}),
"initial_priviliged": initial_priviliged = false,
}
:
{
action_open ?: ((entry : type_entry) => void);
action_toggle_visibility ?: ((entry : type_entry) => void);
} = {}
action_create ?: (() => void);
initial_priviliged ?: boolean;
}
=
{
}
)
{
options = Object.assign(
{
"action_open": (calendar_id) => {},
"action_toggle_visibility": (calendar_id) => {},
},
options
);
super();
this.keys = [];
this.data = {};
entries.forEach(
(entry) => {
const key : string = entry.id.toFixed(0);
this.keys.push(key);
this.data[key] = entry;
}
);
this.action_open = options.action_open;
this.action_toggle_visibility = options.action_toggle_visibility;
// dependencies
this.get_entries = get_entries;
// hooks
this.action_open = action_open;
this.action_toggle_visibility = action_toggle_visibility;
this.action_create = action_create;
// state
this.priviliged = initial_priviliged;
this.container = null;
}
/**
* [implementation]
*/
public async load(
target_element : Element
) : Promise<void>
private static id_encode(
id : _dali.type_calendar_id
)
: string
{
target_element.innerHTML = await _dali.helpers.template_coin(
return id.toFixed(0);
}
/**
*/
private static id_decode(
representation : string
)
: _dali.type_calendar_id
{
return parseInt(representation);
}
/**
*/
public async update(
{
"priviliged": priviliged = null,
}
:
{
priviliged ?: boolean;
}
=
{
}
)
: Promise<void>
{
if (priviliged === null)
{
// do nothing
}
else
{
this.priviliged = priviliged;
}
const data : lib_plankton.map.type_map<_dali.type_calendar_id, type_entry> = lib_plankton.map.hashmap.implementation_map(
lib_plankton.map.hashmap.make(
calendar_id => class_widget_sources.id_encode(calendar_id),
{
"pairs": (
(await this.get_entries())
.map(
entry => (
{
"key": entry.id,
"value": entry,
}
)
)
),
}
)
);
// structure
{
this.container.innerHTML = await _dali.helpers.template_coin(
"widget-sources",
"main",
{
"label_create": lib_plankton.translate.get("widget.sources.create"),
"entries": (
(
await _dali.helpers.promise_row<string>(
this.keys
lib_plankton.map.dump(data)
.map(
(key) => () => {
const entry : type_entry = this.data[key];
(pair) => () => {
return _dali.helpers.template_coin(
"widget-sources",
"entry",
{
"name": entry.name,
"name": pair.value.name,
"label_toggle": lib_plankton.string.coin(
"{{show}}/{{hide}}",
{
@ -104,8 +182,14 @@ namespace _dali.widgets.sources
"color_head": lib_plankton.color.output_hex(
lib_plankton.color.make_hsv(
{
"hue": entry.hue,
"hue": pair.value.hue,
/**
* @todo const and outsource
*/
"saturation": 0.375,
/**
* @todo const and outsource
*/
"value": 0.375,
}
),
@ -113,13 +197,19 @@ namespace _dali.widgets.sources
"color_body": lib_plankton.color.output_hex(
lib_plankton.color.make_hsv(
{
"hue": entry.hue,
"hue": pair.value.hue,
/**
* @todo const and outsource
*/
"saturation": 0.375,
/**
* @todo const and outsource
*/
"value": 0.25,
}
),
),
"rel": key,
"rel": class_widget_sources.id_encode(pair.key),
}
);
}
@ -130,7 +220,18 @@ namespace _dali.widgets.sources
),
}
);
target_element.querySelectorAll(".sources-entry-head").forEach(
this.container.querySelector(".sources").classList.toggle("sources-priviliged", this.priviliged);
}
// listeners
{
this.container.querySelector(".sources-create").addEventListener(
"click",
(event) => {
event.preventDefault();
this.action_create();
}
);
this.container.querySelectorAll(".sources-entry-head").forEach(
(element) => {
element.addEventListener(
"click",
@ -140,13 +241,14 @@ namespace _dali.widgets.sources
);
}
);
target_element.querySelectorAll(".sources-entry-toggle").forEach(
this.container.querySelectorAll(".sources-entry-toggle").forEach(
(element) => {
element.addEventListener(
"click",
() => {
const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
const entry : type_entry = this.data[key];
const key_encoded : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
const calendar_id : _dali.type_calendar_id = class_widget_sources.id_decode(key_encoded);
const entry : type_entry = data.get(calendar_id);
element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-hidden");
element.parentElement.parentElement.parentElement.classList.toggle("sources-entry-open", false);
this.action_toggle_visibility(entry);
@ -154,19 +256,33 @@ namespace _dali.widgets.sources
);
}
);
target_element.querySelectorAll(".sources-entry-edit").forEach(
this.container.querySelectorAll(".sources-entry-edit").forEach(
(element) => {
element.addEventListener(
"click",
(event) => {
const key : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
const entry : type_entry = this.data[key];
const key_encoded : string = element.parentElement.parentElement.parentElement.getAttribute("rel");
const calendar_id : _dali.type_calendar_id = class_widget_sources.id_decode(key_encoded);
const entry : type_entry = data.get(calendar_id);
this.action_open(entry);
}
);
}
);
return Promise.resolve<void>(undefined);
}
}
/**
* [implementation]
*/
public async load(
target_element : Element
)
: Promise<void>
{
this.container = target_element;
await this.update();
}
}

View file

@ -1,3 +1,6 @@
<ul class="sources">
<div class="sources">
<ul class="sources-entries">
{{entries}}
</ul>
</ul>
<a class="sources-create" href="">{{label_create}}</a>
</div>

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,6 @@
<span>{{label_control_count}}</span>
<input type="number"/>
</label>
<input type="submit" class="weekview-control weekview-control-apply" value="{{label_control_apply}}"/>
</div>
<div class="weekview-table">
<table>

View file

@ -32,17 +32,22 @@ ${dir_build}/index.html: \
.PHONY: templates
templates: \
templates-widgets-login \
templates-widgets-sources \
templates-widgets-listview \
templates-widgets-weekview \
templates-widgets-mode_switcher \
templates-widgets-calendar_edit \
templates-widgets-event_edit \
templates-pages-caldav \
templates-pages-calendar_add \
templates-pages-calendar_edit \
templates-pages-event_add \
templates-pages-event_edit \
templates-pages-overview \
templates-pages-login
templates-pages-overview
.PHONY: templates-widgets-login
templates-widgets-login: \
$(wildcard ${dir_source}/widgets/login/templates/*)
@ ${cmd_log} "templates:widgets:login …"
@ ${cmd_mkdir} ${dir_build}/templates/widget-login
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/login/templates/* ${dir_build}/templates/widget-login/
.PHONY: templates-widgets-sources
templates-widgets-sources: \
@ -72,6 +77,20 @@ templates-widgets-mode_switcher: \
@ ${cmd_mkdir} ${dir_build}/templates/widget-mode_switcher
@ ${cmd_cp} -r -u -v ${dir_source}/widgets/mode_switcher/templates/* ${dir_build}/templates/widget-mode_switcher/
.PHONY: templates-widgets-calendar_edit
templates-widgets-calendar_edit: \
$(wildcard ${dir_source}/widgets/calendar_edit/templates/*)
@ ${cmd_log} "templates:widgets:calendar_edit …"
@ ${cmd_mkdir} ${dir_build}/templates/widget-calendar_edit
# @ ${cmd_cp} -r -u -v ${dir_source}/widgets/calendar_edit/templates/* ${dir_build}/templates/widget-calendar_edit/
.PHONY: templates-widgets-event_edit
templates-widgets-event_edit: \
$(wildcard ${dir_source}/pages/event_edit/templates/*)
@ ${cmd_log} "templates:widgets:event_edit …"
@ ${cmd_mkdir} ${dir_build}/templates/widget-event_edit
# @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/widget-uevent_edit/
.PHONY: templates-pages-caldav
templates-pages-caldav: \
$(wildcard ${dir_source}/pages/caldav/templates/*)
@ -79,34 +98,6 @@ templates-pages-caldav: \
@ ${cmd_mkdir} ${dir_build}/templates/caldav
@ ${cmd_cp} -r -u -v ${dir_source}/pages/caldav/templates/* ${dir_build}/templates/caldav/
.PHONY: templates-pages-calendar_add
templates-pages-calendar_add: \
$(wildcard ${dir_source}/pages/calendar_add/templates/*)
@ ${cmd_log} "templates:calendar_add …"
@ ${cmd_mkdir} ${dir_build}/templates/calendar_add
@ ${cmd_cp} -r -u -v ${dir_source}/pages/calendar_add/templates/* ${dir_build}/templates/calendar_add/
.PHONY: templates-pages-calendar_edit
templates-pages-calendar_edit: \
$(wildcard ${dir_source}/pages/calendar_edit/templates/*)
@ ${cmd_log} "templates:calendar_edit …"
@ ${cmd_mkdir} ${dir_build}/templates/calendar_edit
@ ${cmd_cp} -r -u -v ${dir_source}/pages/calendar_edit/templates/* ${dir_build}/templates/calendar_edit/
.PHONY: templates-pages-event_add
templates-pages-event_add: \
$(wildcard ${dir_source}/pages/event_add/templates/*)
@ ${cmd_log} "templates:event_add …"
@ ${cmd_mkdir} ${dir_build}/templates/event_add
@ ${cmd_cp} -r -u -v ${dir_source}/pages/event_add/templates/* ${dir_build}/templates/event_add/
.PHONY: templates-pages-event_edit
templates-pages-event_edit: \
$(wildcard ${dir_source}/pages/event_edit/templates/*)
@ ${cmd_log} "templates:event_edit …"
@ ${cmd_mkdir} ${dir_build}/templates/event_edit
@ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/event_edit/
.PHONY: templates-pages-overview
templates-pages-overview: \
$(wildcard ${dir_source}/pages/overview/templates/*)
@ -114,13 +105,6 @@ templates-pages-overview: \
@ ${cmd_mkdir} ${dir_build}/templates/overview
@ ${cmd_cp} -r -u -v ${dir_source}/pages/overview/templates/* ${dir_build}/templates/overview/
.PHONY: templates-pages-login
templates-pages-login: \
$(wildcard ${dir_source}/pages/login/templates/*)
@ ${cmd_log} "templates:login …"
@ ${cmd_mkdir} ${dir_build}/templates/login
@ ${cmd_cp} -r -u -v ${dir_source}/pages/login/templates/* ${dir_build}/templates/login/
.PHONY: style
style: \
$(wildcard ${dir_source}/style/*)
@ -133,24 +117,23 @@ logic: ${dir_build}/logic.js
${dir_temp}/logic-unlinked.js: \
${dir_lib}/plankton/plankton.d.ts \
${dir_source}/base/helpers.ts \
${dir_source}/base/widget.ts \
${dir_source}/base/types.ts \
${dir_source}/base/functions.ts \
${dir_source}/resources/conf.ts \
${dir_source}/resources/backend.ts \
${dir_source}/base.ts \
${dir_source}/types.ts \
${dir_source}/model.ts \
${dir_source}/helpers.ts \
${dir_source}/widgets/login/logic.ts \
${dir_source}/widgets/menu/logic.ts \
${dir_source}/widgets/sources/logic.ts \
${dir_source}/widgets/listview/logic.ts \
${dir_source}/widgets/weekview/logic.ts \
${dir_source}/widgets/mode_switcher/logic.ts \
${dir_source}/pages/login/logic.ts \
${dir_source}/pages/logout/logic.ts \
${dir_source}/widgets/calendar_edit/logic.ts \
${dir_source}/widgets/event_edit/logic.ts \
${dir_source}/overlay.ts \
${dir_source}/pages/caldav/logic.ts \
${dir_source}/pages/oidc_finish/logic.ts \
${dir_source}/pages/calendar_add/logic.ts \
${dir_source}/pages/calendar_edit/logic.ts \
${dir_source}/pages/event_add/logic.ts \
${dir_source}/pages/event_edit/logic.ts \
${dir_source}/pages/overview/logic.ts \
${dir_source}/main.ts
@ ${cmd_log} "logic | compile …"

View file

@ -14,6 +14,8 @@ modules="${modules} json"
modules="${modules} string"
modules="${modules} random"
modules="${modules} map"
modules="${modules} set"
modules="${modules} cache"
modules="${modules} color"
# modules="${modules} xml"
modules="${modules} map"
@ -23,6 +25,7 @@ modules="${modules} url"
modules="${modules} pit"
modules="${modules} www_form"
modules="${modules} translate"
modules="${modules} zoo-widget"
modules="${modules} zoo-page"
modules="${modules} zoo-form"
modules="${modules} zoo-input"