diff --git a/lib/plankton/plankton.js b/lib/plankton/plankton.js index 64e504d..0a4b816 100644 --- a/lib/plankton/plankton.js +++ b/lib/plankton/plankton.js @@ -9940,7 +9940,7 @@ var lib_plankton; h = 0; } else if (q === r) { - h = ((0 / 3) + ((g - b) / (c * 6))); + h = ((0 / 3) + lib_plankton.math.mod((g - b) / (c * 6), 1)); } else if (q === g) { h = ((1 / 3) + ((b - r) / (c * 6))); diff --git a/misc/conf-example.json b/misc/conf-example.json index 7f8190c..cf5b37e 100644 --- a/misc/conf-example.json +++ b/misc/conf-example.json @@ -8,6 +8,6 @@ }, "misc": { "oidc_redirect_uri_template": "http://localhost:8888/#oidc_finish,session_key={{session_key}}", - "use_central_europe_specific_datetime_inputs": false + "use_central_europe_specific_datetime_inputs": true } } diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index 1ddbdb1..52bdc5b 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -18,6 +18,7 @@ "common.edit": "bearbeiten", "common.show": "zeigen", "common.hide": "ausblenden", + "common.cancel": "abbrechen", "access_level.none": "nichts", "access_level.view": "nur lesen", "access_level.edit": "lesen und bearbeiten", @@ -49,6 +50,11 @@ "widget.weekview.controls.week": "Woche", "widget.weekview.controls.count": "Anzahl", "widget.weekview.controls.apply": "Laden", + "widget.calendar_edit.actions.change": "ändern", + "widget.calendar_edit.actions.remove": "löschen", + "widget.event_edit.actions.add": "anlegen", + "widget.event_edit.actions.change": "ändern", + "widget.event_edit.actions.remove": "löschen", "page.login.title": "Anmelden", "page.login.internal.name": "Name", "page.login.internal.password": "Kennwort", @@ -70,14 +76,9 @@ "page.calendar_add.actions.do": "anlegen", "page.calendar_edit.title.regular": "Kalendar bearbeiten", "page.calendar_edit.title.read_only": "Kalendar-Details", - "page.calendar_edit.actions.change": "ändern", - "page.calendar_edit.actions.remove": "löschen", "page.event_add.title": "Termin anlegen", - "page.event_add.actions.do": "anlegen", "page.event_edit.title.regular": "Termin bearbeiten", "page.event_edit.title.read_only": "Termin-Details", - "page.event_edit.actions.change": "ändern", - "page.event_edit.actions.remove": "löschen", "page.overview.title": "Übersicht", "page.overview.login_hint": "anmelden um nicht-öffentliche Termine zu sehen", "page.overview.mode.week": "Wochen-Ansicht", diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 25ad7bf..023e8d2 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -18,6 +18,7 @@ "common.edit": "edit", "common.show": "show", "common.hide": "hide", + "common.cancel": "cancel", "access_level.none": "none", "access_level.view": "read only", "access_level.edit": "read and write", @@ -49,6 +50,11 @@ "widget.weekview.controls.week": "Week", "widget.weekview.controls.count": "Count", "widget.weekview.controls.apply": "Load", + "widget.calendar_edit.actions.change": "change", + "widget.calendar_edit.actions.remove": "delete", + "widget.event_edit.actions.add": "add", + "widget.event_edit.actions.change": "change", + "widget.event_edit.actions.remove": "delete", "page.login.title": "Login", "page.login.internal.name": "name", "page.login.internal.password": "password", @@ -69,15 +75,10 @@ "page.calendar_add.title": "Add calendar", "page.calendar_add.actions.do": "anlegen", "page.event_add.title": "Add event", - "page.event_add.actions.do": "add", "page.calendar_edit.title.regular": "Edit calendar", "page.calendar_edit.title.read_only": "Calendar details", - "page.calendar_edit.actions.change": "change", - "page.calendar_edit.actions.remove": "delete", "page.event_edit.title.regular": "Edit event", "page.event_edit.title.read_only": "Event details", - "page.event_edit.actions.change": "change", - "page.event_edit.actions.remove": "delete", "page.overview.title": "Overview", "page.overview.login_hint": "log in to view non-public events", "page.overview.mode.week": "week view", diff --git a/source/index.html.tpl b/source/index.html.tpl index e8eb5f4..d8151a6 100644 --- a/source/index.html.tpl +++ b/source/index.html.tpl @@ -31,6 +31,10 @@ document.addEventListener( +
+
+
+
diff --git a/source/main.ts b/source/main.ts index 1713e10..6998722 100644 --- a/source/main.ts +++ b/source/main.ts @@ -109,6 +109,7 @@ namespace _dali } ); await update(); + await _dali.overlay.initialize(); lib_plankton.call.loop( () => { update(); diff --git a/source/overlay.ts b/source/overlay.ts new file mode 100644 index 0000000..6195c85 --- /dev/null +++ b/source/overlay.ts @@ -0,0 +1,75 @@ +namespace _dali.overlay +{ + + /** + */ + function get_container_element( + ) : HTMLElement + { + return document.querySelector("#overlay"); + } + + + /** + */ + export function get_content_element( + ) : HTMLElement + { + return document.querySelector("#overlay_content"); + } + + + /** + */ + export function clear( + ) : void + { + get_content_element().innerHTML = ""; + } + + + /** + */ + export function toggle( + { + "mode": mode = null, + } + : + { + mode ?: (null | boolean); + } + = + { + } + ) : void + { + get_container_element().classList.toggle("overlay_active", mode ?? undefined); + } + + + /** + */ + export function initialize( + ) : Promise + { + clear(); + const container_element : HTMLElement = get_container_element(); + /* + container_element.addEventListener( + "click", + (event) => { + if (event.target == container_element) + { + toggle({"mode": false}); + } + else + { + // do nothing + } + } + ); + */ + return Promise.resolve(undefined); + } + +} diff --git a/source/pages/calendar_edit/logic.ts b/source/pages/calendar_edit/logic.ts index 0ed083d..8221f13 100644 --- a/source/pages/calendar_edit/logic.ts +++ b/source/pages/calendar_edit/logic.ts @@ -16,170 +16,51 @@ namespace _dali.pages "label": lib_plankton.translate.get("page.calendar_edit.title.regular") } ); - const form : lib_plankton.zoo_form.class_form< - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - }, - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - } - > = new lib_plankton.zoo_form.class_form< - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - }, - { - name : string; - hue : float; - access : { - public : boolean; - default_level : _dali.type.enum_access_level; - attributed : lib_plankton.map.type_map< - _dali.type.user_id, - _dali.type.enum_access_level - >; - }; - } - >( - (value) => value, - (raw) => raw, - new lib_plankton.zoo_input.class_input_group( - [ - { - "name": "name", - "input": new lib_plankton.zoo_input.class_input_text(), - "label": lib_plankton.translate.get("calendar.name") - }, - { - "name": "hue", - "input": new lib_plankton.zoo_input.class_input_hue( - ), - "label": lib_plankton.translate.get("calendar.hue"), - }, - { - "name": "access", - "input": new lib_plankton.zoo_input.class_input_group( - [ - { - "name": "public", - "input": new lib_plankton.zoo_input.class_input_checkbox(), - "label": lib_plankton.translate.get("calendar.access.public"), - }, - { - "name": "default_level", - "input": _dali.helpers.input_access_level(), - "label": lib_plankton.translate.get("calendar.access.default_level"), - }, - { - "name": "attributed", - "input": await _dali.helpers.input_attributed_access(), - "label": lib_plankton.translate.get("calendar.access.attributed"), - }, - ] - ), - "label": lib_plankton.translate.get("calendar.access.access"), - }, - ] - ), - ( - read_only - ? - [ - ] - : - [ - { - "label": lib_plankton.translate.get("page.calendar_edit.actions.change"), - "procedure": async (get_value, get_representation) => { - const data : any = await get_value(); - try { - await _dali.backend.calendar_change( - calendar_id, - data - ); - lib_plankton.zoo_page.set( - { - "name": "overview", - "parameters": {} - } - ); - } - catch (error) { - // do nothing - /* - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { - } - } - ); - */ - } - } - }, - { - "label": lib_plankton.translate.get("page.calendar_edit.actions.remove"), - "procedure": async (get_value, get_representation) => { - try { - await _dali.backend.calendar_remove( - calendar_id - ); - lib_plankton.zoo_page.set( - { - "name": "overview", - "parameters": {} - } - ); - } - catch (error) { - // do nothing - /* - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { - } - } - ); - */ - } - } - }, - ] - ) - ); - await form.setup(document.querySelector("#calendar_edit_form")); const calendar_object : _dali.type.calendar_object = await _dali.backend.calendar_get( calendar_id ); - await form.input_write(calendar_object); + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + { + "read_only": read_only, + "action_change": (data) => { + _dali.backend.calendar_change( + calendar_id, + data + ) + .then( + () => { + lib_plankton.zoo_page.set( + { + "name": "overview", + "parameters": {} + } + ); + } + ); + }, + "action_remove": (data) => { + _dali.backend.calendar_remove( + calendar_id + ) + .then( + () => { + lib_plankton.zoo_page.set( + { + "name": "overview", + "parameters": {} + } + ); + } + ); + }, + "initial_value": { + "name": calendar_object.name, + "hue": calendar_object.hue, + "access": calendar_object.access, + }, + } + ); + await widget.load(document.querySelector("#calendar_edit_form")); return Promise.resolve(undefined); } ); diff --git a/source/pages/event_add/logic.ts b/source/pages/event_add/logic.ts deleted file mode 100644 index f5b5d90..0000000 --- a/source/pages/event_add/logic.ts +++ /dev/null @@ -1,235 +0,0 @@ -namespace _dali.pages -{ - - /** - */ - lib_plankton.zoo_page.register( - "event_add", - async (parameters, target_element) => { - const calendar_id : (null | int) = ( - ("calendar_id" in parameters) - ? - parseInt(parameters["calendar_id"]) - : - null - ); - const year : (null | int) = ( - ("year" in parameters) - ? - parseInt(parameters["year"]) - : - null - ); - const month : (null | int) = ( - ("month" in parameters) - ? - parseInt(parameters["month"]) - : - null - ); - const day : (null | int) = ( - ("day" in parameters) - ? - parseInt(parameters["day"]) - : - null - ); - const date : lib_plankton.pit.type_date = ( - ( - (year !== null) - && - (month !== null) - && - (day !== null) - ) - ? - { - "year": year, - "month": month, - "day": day, - } - : - lib_plankton.pit.to_datetime(lib_plankton.pit.now()).date - ); - target_element.innerHTML = ""; - target_element.innerHTML = await _dali.helpers.template_coin( - "event_add", - "default", - { - "label": lib_plankton.translate.get("page.event_add.title") - } - ); - const form : lib_plankton.zoo_form.class_form< - { - calendar_id : _dali.type.calendar_id; - event_object : _dali.type.event_object; - }, - { - calendar_id : string; - name : string; - begin : lib_plankton.pit.type_datetime; - end : (null | lib_plankton.pit.type_datetime); - location : (null | string); - link : (null | string); - description : (null | string); - } - > = new lib_plankton.zoo_form.class_form< - { - calendar_id : _dali.type.calendar_id; - event_object : _dali.type.event_object; - }, - { - calendar_id : string; - name : string; - begin : lib_plankton.pit.type_datetime; - end : (null | lib_plankton.pit.type_datetime); - location : (null | string); - link : (null | string); - description : (null | string); - } - >( - (value) => ({ - "calendar_id": value.calendar_id.toFixed(0), - "name": value.event_object.name, - "begin": value.event_object.begin, - "end": value.event_object.end, - "location": value.event_object.location, - "link": value.event_object.link, - "description": value.event_object.description, - }), - (representation) => ({ - "calendar_id": parseInt(representation.calendar_id), - "event_object": { - "name": representation.name, - "begin": representation.begin, - "end": representation.end, - "location": representation.location, - "link": representation.link, - "description": representation.description, - } - }), - new lib_plankton.zoo_input.class_input_group( - [ - { - "name": "calendar_id", - "input": new lib_plankton.zoo_input.class_input_selection( - ( - (await _dali.backend.calendar_list()) - .filter( - (entry) => ( - (entry.access_level === _dali.type.enum_access_level.edit) - || - (entry.access_level === _dali.type.enum_access_level.admin) - ) - ) - .map( - (entry) => ({ - "value": entry.id.toFixed(0), - "label": entry.name, - }) - ) - ) - ), - "label": lib_plankton.translate.get("calendar.calendar") - }, - { - "name": "name", - "input": new lib_plankton.zoo_input.class_input_text( - ), - "label": lib_plankton.translate.get("event.name") - }, - { - "name": "begin", - "input": _dali.helpers.datetime_input(), - "label": lib_plankton.translate.get("event.begin") - }, - { - "name": "end", - "input": new lib_plankton.zoo_input.class_input_soft( - _dali.helpers.datetime_input() - ), - "label": lib_plankton.translate.get("event.end") - }, - { - "name": "location", - "input": new lib_plankton.zoo_input.class_input_soft( - new lib_plankton.zoo_input.class_input_text( - ) - ), - "label": lib_plankton.translate.get("event.location") - }, - { - "name": "link", - "input": new lib_plankton.zoo_input.class_input_soft( - new lib_plankton.zoo_input.class_input_text( - ) - ), - "label": lib_plankton.translate.get("event.link") - }, - { - "name": "description", - "input": new lib_plankton.zoo_input.class_input_soft( - new lib_plankton.zoo_input.class_input_textarea( - ) - ), - "label": lib_plankton.translate.get("event.description") - }, - ] - ), - [ - { - "label": lib_plankton.translate.get("page.event_add.actions.do"), - "target": "submit", - "procedure": async (get_value, get_representation) => { - const value : any = await get_value(); - try { - await _dali.backend.calendar_event_add( - value.calendar_id, - value.event_object - ); - lib_plankton.zoo_page.set( - { - "name": "overview", - "parameters": {} - } - ); - } - catch (error) { - // do nothing - /* - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { - } - } - ); - */ - } - } - }, - ] - ); - await form.setup(document.querySelector("#event_add_form")); - await form.input_write( - { - "calendar_id": (calendar_id ?? 0), - "event_object": { - "name": "", - "begin": { - "timezone_shift": 0, - "date": date, - "time": null - }, - "end": null, - "location": null, - "link": null, - "description": null, - } - } - ); - return Promise.resolve(undefined); - } - ); - -} diff --git a/source/pages/event_add/templates/default.html.tpl b/source/pages/event_add/templates/default.html.tpl deleted file mode 100644 index 3cfad06..0000000 --- a/source/pages/event_add/templates/default.html.tpl +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{label}}

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

{{label}}

-
-
-
diff --git a/source/pages/overview/logic.ts b/source/pages/overview/logic.ts index e6dd23b..e798974 100644 --- a/source/pages/overview/logic.ts +++ b/source/pages/overview/logic.ts @@ -17,6 +17,13 @@ namespace _dali.pages.overview target_element.querySelector("#overview").classList.toggle("overview-compact", compact); }; + /** + * @todo geschickter bauen (MVC, MVVM, …) + */ + const update = () => { + lib_plankton.zoo_page.reload(); + }; + // exec target_element.innerHTML = await _dali.helpers.template_coin( "overview", @@ -85,6 +92,7 @@ namespace _dali.pages.overview data, { "action_open": (entry) => { + let read_only : boolean; switch (entry.access_level) { case _dali.type.enum_access_level.none: @@ -95,31 +103,60 @@ namespace _dali.pages.overview case _dali.type.enum_access_level.edit: case _dali.type.enum_access_level.view: { - lib_plankton.zoo_page.set( - { - "name": "calendar_edit", - "parameters": { - "read_only": "yes", - "calendar_id": entry.id, - } - } - ); + read_only = true; break; } case _dali.type.enum_access_level.admin: { - lib_plankton.zoo_page.set( - { - "name": "calendar_edit", - "parameters": { - "read_only": "no", - "calendar_id": entry.id, - } - } - ); + read_only = false; break; } } + (async () => { + const calendar_id : _dali.type.calendar_id = entry.id; + const calendar_object : _dali.type.calendar_object = await _dali.backend.calendar_get( + calendar_id + ); + const widget = new _dali.widgets.calendar_edit.class_widget_calendar_edit( + { + "read_only": read_only, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_change": (data) => { + _dali.backend.calendar_change( + calendar_id, + data + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ); + }, + "action_remove": (data) => { + _dali.backend.calendar_remove( + calendar_id + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ); + }, + "initial_value": { + "name": calendar_object.name, + "hue": calendar_object.hue, + "access": calendar_object.access, + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }, "action_toggle_visibility": (entry) => { widget_weekview.toggle_visibility(entry.id); @@ -139,6 +176,7 @@ namespace _dali.pages.overview } ); const action_select_event = (calendar_id, access_level, event_id) => { + let read_only : boolean; switch (access_level) { case _dali.type.enum_access_level.none: @@ -148,34 +186,90 @@ namespace _dali.pages.overview } case _dali.type.enum_access_level.view: { - lib_plankton.zoo_page.set( - { - "name": "event_edit", - "parameters": { - "read_only": "yes", - "calendar_id": calendar_id, - "event_id": event_id, - } - } - ); + read_only = true; break; } case _dali.type.enum_access_level.edit: case _dali.type.enum_access_level.admin: { - lib_plankton.zoo_page.set( - { - "name": "event_edit", - "parameters": { - "read_only": "no", - "calendar_id": calendar_id, - "event_id": event_id, - } - } - ); + read_only = false; break; } } + (async () => { + const event_object : _dali.type.event_object = await _dali.backend.calendar_event_get( + calendar_id, + event_id + ); + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + { + "calendar_id": calendar_id, + "event_name": event_object.name, + "event_begin": event_object.begin, + "event_end": event_object.end, + "event_location": event_object.location, + "event_link": event_object.link, + "event_description": event_object.description, + }, + { + "read_only": read_only, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_change": (data) => { + _dali.backend.calendar_event_change( + calendar_id, + event_id, + { + "name": data.event_name, + "begin": data.event_begin, + "end": data.event_end, + "location": data.event_location, + "link": data.event_link, + "description": data.event_description, + } + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_change.error", + {"details": String(reason)} + ); + } + ); + }, + "action_remove": () => { + _dali.backend.calendar_event_remove( + calendar_id, + event_id + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + lib_plankton.log.warning( + "dali.overview.event_remove_error", + {"details": String(reason)} + ); + } + ); + }, + } + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }; // listview { @@ -210,17 +304,76 @@ namespace _dali.pages.overview { "action_select_event": action_select_event, "action_select_day": (date) => { - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { + (async () => { + const widget = new _dali.widgets.event_edit.class_widget_event_edit( + { "calendar_id": null, - "year": date.year, - "month": date.month, - "day": date.day, + "event_name": "", + "event_begin": lib_plankton.call.convey( + date, + [ + x => ({ + "timezone_shift": 0, + "date": date, + "time": {"hour": 12, "minute": 0, "second": 0} + }), + lib_plankton.pit.from_datetime, + x => lib_plankton.pit.shift_hour(x, 0), + lib_plankton.pit.to_datetime, + ] + ), + "event_end": lib_plankton.call.convey( + date, + [ + x => ({ + "timezone_shift": 0, + "date": date, + "time": {"hour": 12, "minute": 0, "second": 0} + }), + lib_plankton.pit.from_datetime, + x => lib_plankton.pit.shift_hour(x, +1), + lib_plankton.pit.to_datetime, + ] + ), + "event_location": null, + "event_link": null, + "event_description": null, + }, + { + "read_only": false, + "action_cancel": () => { + _dali.overlay.toggle({"mode": false}); + }, + "action_add": (data) => { + _dali.backend.calendar_event_add( + data.calendar_id, + { + "name": data.event_name, + "begin": data.event_begin, + "end": data.event_end, + "location": data.event_location, + "link": data.event_link, + "description": data.event_description, + } + ) + .then( + () => { + update(); + _dali.overlay.toggle({"mode": false}); + } + ) + .catch( + (reason) => { + // todo + } + ); + }, } - } - ); + ); + _dali.overlay.clear(); + _dali.overlay.toggle({"mode": true}); + await widget.load(_dali.overlay.get_content_element()); + }) (); }, } ) diff --git a/source/resources/backend.ts b/source/resources/backend.ts index 1164246..9991f92 100644 --- a/source/resources/backend.ts +++ b/source/resources/backend.ts @@ -547,6 +547,7 @@ namespace _dali.backend /** + * @todo Möglichkeit den Kalender zu ändern */ export async function calendar_event_change( calendar_id : _dali.type.calendar_id, diff --git a/source/style/main.css b/source/style/main.css index e1d417e..ea384f0 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -20,6 +20,39 @@ header margin-bottom: 16px; } +#overlay +{ + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + z-index: 2; +} + +#overlay_content +{ + position: absolute; + top: 50%; + left: 50%; + + transform: translate(-50%,-50%); + -ms-transform: translate(-50%,-50%); + + padding: 32px; + + background-color: hsl(0, 0%, 12.5%); + color: hsl(0, 0%, 100%); +} + +#overlay:not(.overlay_active) +{ + display: none; +} + nav > ul { list-style-type: none; diff --git a/source/widgets/calendar_edit/logic.ts b/source/widgets/calendar_edit/logic.ts new file mode 100644 index 0000000..ac45f84 --- /dev/null +++ b/source/widgets/calendar_edit/logic.ts @@ -0,0 +1,217 @@ +namespace _dali.widgets.calendar_edit +{ + + /** + */ + export type type_value = { + name : string; + hue : float; + access : { + public : boolean; + default_level : _dali.type.enum_access_level; + attributed : lib_plankton.map.type_map< + _dali.type.user_id, + _dali.type.enum_access_level + >; + }; + }; + + + /** + */ + export class class_widget_calendar_edit + implements lib_plankton.zoo_widget.interface_widget + { + + /** + */ + private read_only : boolean; + + + /** + */ + private action_cancel ?: (null | (() => void)); + + + /** + */ + private action_change ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_remove ?: (null | ((value : type_value) => void)); + + + /** + */ + private initial_value : (null | type_value); + + + /** + */ + public constructor( + { + "read_only": read_only = false, + "action_cancel": action_cancel = null, + "action_change": action_change = null, + "action_remove": action_remove = null, + "initial_value": initial_value = null, + } + : + { + read_only ?: boolean; + action_cancel ?: (null | (() => void)); + action_change ?: (null | ((value : type_value) => void)); + action_remove ?: (null | ((value : type_value) => void)); + initial_value ?: (null | type_value); + } + = + { + } + ) + { + this.read_only = read_only; + this.action_cancel = action_cancel; + this.action_change = action_change; + this.action_remove = action_remove; + this.initial_value = initial_value; + } + + + /** + * [implementation] + */ + public async load( + target_element : HTMLElement + ) : Promise + { + const form : lib_plankton.zoo_form.class_form< + type_value, + type_value + > = new lib_plankton.zoo_form.class_form< + type_value, + type_value + >( + (value) => value, + (raw) => raw, + new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "name", + "input": new lib_plankton.zoo_input.class_input_text(), + "label": lib_plankton.translate.get("calendar.name") + }, + { + "name": "hue", + "input": new lib_plankton.zoo_input.class_input_hue( + ), + "label": lib_plankton.translate.get("calendar.hue"), + }, + { + "name": "access", + "input": new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "public", + "input": new lib_plankton.zoo_input.class_input_checkbox(), + "label": lib_plankton.translate.get("calendar.access.public"), + }, + { + "name": "default_level", + "input": _dali.helpers.input_access_level(), + "label": lib_plankton.translate.get("calendar.access.default_level"), + }, + { + "name": "attributed", + "input": await _dali.helpers.input_attributed_access(), + "label": lib_plankton.translate.get("calendar.access.attributed"), + }, + ] + ), + "label": lib_plankton.translate.get("calendar.access.access"), + }, + ] + ), + ( + [] + // cancel + .concat( + (! (this.action_cancel === null)) + ? + [ + { + "label": lib_plankton.translate.get("common.cancel"), + "procedure": async () => { + this.action_cancel(); + } + }, + ] + : + [] + ) + // change + .concat( + ((! this.read_only) && (! (this.action_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.calendar_edit.actions.change"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_change(value); + } + }, + ] + : + [] + ) + // remove + .concat( + ((! this.read_only) && (! (this.action_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.calendar_edit.actions.remove"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_remove(value); + } + }, + ] + : + [] + ) + ) + ); + await form.setup(target_element); + await form.input_write( + (! (this.initial_value === null)) + ? + this.initial_value + : + { + "name": "", + "hue": lib_plankton.random.generate_unit(), + "access": { + "public": false, + "default_level": _dali.type.enum_access_level.view, + "attributed": lib_plankton.map.hashmap.implementation_map< + _dali.type.user_id, + _dali.type.enum_access_level + >( + lib_plankton.map.hashmap.make< + _dali.type.user_id, + _dali.type.enum_access_level + >( + user_id => user_id.toFixed(0), + ) + ), + }, + } + ); + } + + } + +} diff --git a/source/widgets/event_edit/logic.ts b/source/widgets/event_edit/logic.ts new file mode 100644 index 0000000..7d1b942 --- /dev/null +++ b/source/widgets/event_edit/logic.ts @@ -0,0 +1,282 @@ +namespace _dali.widgets.event_edit +{ + + /** + */ + export type type_value = { + calendar_id : (null | _dali.type.calendar_id); + event_name : string; + event_begin : lib_plankton.pit.type_datetime; + event_end : (null | lib_plankton.pit.type_datetime); + event_location : (null | string); + event_link : (null | string); + event_description : (null | string); + }; + + + /** + */ + export type type_representation = { + calendar_id : string; + event_name : string; + event_begin : lib_plankton.pit.type_datetime; + event_end : (null | lib_plankton.pit.type_datetime); + event_location : (null | string); + event_link : (null | string); + event_description : (null | string); + }; + + + /** + */ + export class class_widget_event_edit + implements lib_plankton.zoo_widget.interface_widget + { + + /** + */ + private read_only : boolean; + + + /** + */ + private action_cancel ?: (null | (() => void)); + + + /** + */ + private action_add ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_change ?: (null | ((value : type_value) => void)); + + + /** + */ + private action_remove ?: (null | ((value : type_value) => void)); + + + /** + */ + private initial_value : type_value; + + + /** + */ + public constructor( + initial_value : type_value, + { + "read_only": read_only = false, + "action_cancel": action_cancel = null, + "action_add": action_add = null, + "action_change": action_change = null, + "action_remove": action_remove = null, + } + : + { + read_only ?: boolean; + action_cancel ?: (null | (() => void)); + action_add ?: (null | ((value : type_value) => void)); + action_change ?: (null | ((value : type_value) => void)); + action_remove ?: (null | ((value : type_value) => void)); + } + = + { + } + ) + { + this.read_only = read_only; + this.action_cancel = action_cancel; + this.action_add = action_add; + this.action_change = action_change; + this.action_remove = action_remove; + this.initial_value = initial_value; + } + + + /** + * [implementation] + */ + public async load( + target_element : HTMLElement + ) : Promise + { + const available_calendars : Array< + { + id : int; + name : string; + hue : float; + access_level : _dali.type.enum_access_level; + } + > = ( + (await _dali.backend.calendar_list()) + .filter( + (entry) => ( + (entry.access_level === _dali.type.enum_access_level.edit) + || + (entry.access_level === _dali.type.enum_access_level.admin) + ) + ) + ); + const form : lib_plankton.zoo_form.class_form< + type_value, + type_representation + > = new lib_plankton.zoo_form.class_form< + type_value, + type_representation + >( + (value) => ({ + "calendar_id": (value.calendar_id ?? available_calendars[0].id).toFixed(0), + "event_name": value.event_name, + "event_begin": value.event_begin, + "event_end": value.event_end, + "event_location": value.event_location, + "event_link": value.event_link, + "event_description": value.event_description, + }), + (representation) => ({ + "calendar_id": parseInt(representation.calendar_id), + "event_name": representation.event_name, + "event_begin": representation.event_begin, + "event_end": representation.event_end, + "event_location": representation.event_location, + "event_link": representation.event_link, + "event_description": representation.event_description, + }), + new lib_plankton.zoo_input.class_input_group( + [ + { + "name": "calendar_id", + "input": new lib_plankton.zoo_input.class_input_selection( + ( + available_calendars + .map( + (entry) => ({ + "value": entry.id.toFixed(0), + "label": entry.name, + }) + ) + ) + ), + "label": lib_plankton.translate.get("calendar.calendar") + }, + { + "name": "event_name", + "input": new lib_plankton.zoo_input.class_input_text( + ), + "label": lib_plankton.translate.get("event.name") + }, + { + "name": "event_begin", + "input": _dali.helpers.datetime_input(), + "label": lib_plankton.translate.get("event.begin") + }, + { + "name": "event_end", + "input": new lib_plankton.zoo_input.class_input_soft( + _dali.helpers.datetime_input() + ), + "label": lib_plankton.translate.get("event.end") + }, + { + "name": "event_location", + "input": new lib_plankton.zoo_input.class_input_soft( + new lib_plankton.zoo_input.class_input_text( + ) + ), + "label": lib_plankton.translate.get("event.location") + }, + { + "name": "event_link", + "input": new lib_plankton.zoo_input.class_input_soft( + new lib_plankton.zoo_input.class_input_text( + ) + ), + "label": lib_plankton.translate.get("event.link") + }, + { + "name": "event_description", + "input": new lib_plankton.zoo_input.class_input_soft( + new lib_plankton.zoo_input.class_input_textarea( + ) + ), + "label": lib_plankton.translate.get("event.description") + }, + ] + ), + ( + [] + // cancel + .concat( + (! (this.action_cancel === null)) + ? + [ + { + "label": lib_plankton.translate.get("common.cancel"), + "procedure": async () => { + this.action_cancel(); + } + }, + ] + : + [] + ) + // add + .concat( + ((! this.read_only) && (! (this.action_add === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.event_edit.actions.add"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_add(value); + } + }, + ] + : + [] + ) + // change + .concat( + ((! this.read_only) && (! (this.action_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.event_edit.actions.change"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_change(value); + } + }, + ] + : + [] + ) + // remove + .concat( + ((! this.read_only) && (! (this.action_change === null))) + ? + [ + { + "label": lib_plankton.translate.get("widget.event_edit.actions.remove"), + "procedure": async (get_value, get_representation) => { + const value : type_value = await get_value(); + this.action_remove(value); + } + }, + ] + : + [] + ) + ) + ); + await form.setup(target_element); + await form.input_write(this.initial_value); + } + + } + +} diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts index e788043..c6a4484 100644 --- a/source/widgets/weekview/logic.ts +++ b/source/widgets/weekview/logic.ts @@ -833,6 +833,26 @@ namespace _dali.widgets.weekview } + /** + */ + private react_on_control_change( + dom_context : Element + ) : void + { + const year : int = parseInt((dom_context.querySelector(".weekview-control-year > input") as HTMLInputElement).value); + const week : int = parseInt((dom_context.querySelector(".weekview-control-week > input") as HTMLInputElement).value); + const count : int = parseInt((dom_context.querySelector(".weekview-control-count > input") as HTMLInputElement).value); + this.update( + year, + week, + count, + { + "update_controls": false, + } + ); + } + + /** */ public toggle_visibility( @@ -886,19 +906,28 @@ namespace _dali.widgets.weekview "click", (event) => { event.preventDefault(); - const year : int = parseInt((target_element.querySelector(".weekview-control-year > input") as HTMLInputElement).value); - const week : int = parseInt((target_element.querySelector(".weekview-control-week > input") as HTMLInputElement).value); - const count : int = parseInt((target_element.querySelector(".weekview-control-count > input") as HTMLInputElement).value); - this.update( - year, - week, - count, - { - "update_controls": false, - } - ); + this.react_on_control_change(target_element); } ); + if (false) + { + [ + "year", + "week", + "count", + ].forEach( + (name) => { + const selector : string = (".weekview-control-" + name + " > input"); + (target_element.querySelector(selector) as HTMLInputElement).addEventListener( + "change", + (event) => { + event.preventDefault(); + this.react_on_control_change(target_element); + } + ); + } + ); + } } // table { diff --git a/tools/makefile b/tools/makefile index dcc4413..89727f0 100644 --- a/tools/makefile +++ b/tools/makefile @@ -36,11 +36,11 @@ templates: \ templates-widgets-listview \ templates-widgets-weekview \ templates-widgets-mode_switcher \ + templates-widgets-calendar_edit \ + templates-widgets-event_edit \ templates-pages-caldav \ templates-pages-calendar_add \ templates-pages-calendar_edit \ - templates-pages-event_add \ - templates-pages-event_edit \ templates-pages-overview \ templates-pages-login @@ -72,6 +72,20 @@ templates-widgets-mode_switcher: \ @ ${cmd_mkdir} ${dir_build}/templates/widget-mode_switcher @ ${cmd_cp} -r -u -v ${dir_source}/widgets/mode_switcher/templates/* ${dir_build}/templates/widget-mode_switcher/ +.PHONY: templates-widgets-calendar_edit +templates-widgets-calendar_edit: \ + $(wildcard ${dir_source}/widgets/calendar_edit/templates/*) + @ ${cmd_log} "templates:widgets:calendar_edit …" + @ ${cmd_mkdir} ${dir_build}/templates/widget-calendar_edit + # @ ${cmd_cp} -r -u -v ${dir_source}/widgets/calendar_edit/templates/* ${dir_build}/templates/widget-calendar_edit/ + +.PHONY: templates-widgets-event_edit +templates-widgets-event_edit: \ + $(wildcard ${dir_source}/pages/event_edit/templates/*) + @ ${cmd_log} "templates:widgets:event_edit …" + @ ${cmd_mkdir} ${dir_build}/templates/widget-event_edit + # @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/widget-uevent_edit/ + .PHONY: templates-pages-caldav templates-pages-caldav: \ $(wildcard ${dir_source}/pages/caldav/templates/*) @@ -93,20 +107,6 @@ templates-pages-calendar_edit: \ @ ${cmd_mkdir} ${dir_build}/templates/calendar_edit @ ${cmd_cp} -r -u -v ${dir_source}/pages/calendar_edit/templates/* ${dir_build}/templates/calendar_edit/ -.PHONY: templates-pages-event_add -templates-pages-event_add: \ - $(wildcard ${dir_source}/pages/event_add/templates/*) - @ ${cmd_log} "templates:event_add …" - @ ${cmd_mkdir} ${dir_build}/templates/event_add - @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_add/templates/* ${dir_build}/templates/event_add/ - -.PHONY: templates-pages-event_edit -templates-pages-event_edit: \ - $(wildcard ${dir_source}/pages/event_edit/templates/*) - @ ${cmd_log} "templates:event_edit …" - @ ${cmd_mkdir} ${dir_build}/templates/event_edit - @ ${cmd_cp} -r -u -v ${dir_source}/pages/event_edit/templates/* ${dir_build}/templates/event_edit/ - .PHONY: templates-pages-overview templates-pages-overview: \ $(wildcard ${dir_source}/pages/overview/templates/*) @@ -142,14 +142,15 @@ ${dir_temp}/logic-unlinked.js: \ ${dir_source}/widgets/listview/logic.ts \ ${dir_source}/widgets/weekview/logic.ts \ ${dir_source}/widgets/mode_switcher/logic.ts \ + ${dir_source}/widgets/calendar_edit/logic.ts \ + ${dir_source}/widgets/event_edit/logic.ts \ + ${dir_source}/overlay.ts \ ${dir_source}/pages/login/logic.ts \ ${dir_source}/pages/logout/logic.ts \ ${dir_source}/pages/caldav/logic.ts \ ${dir_source}/pages/oidc_finish/logic.ts \ ${dir_source}/pages/calendar_add/logic.ts \ ${dir_source}/pages/calendar_edit/logic.ts \ - ${dir_source}/pages/event_add/logic.ts \ - ${dir_source}/pages/event_edit/logic.ts \ ${dir_source}/pages/overview/logic.ts \ ${dir_source}/main.ts @ ${cmd_log} "logic | compile …"