From 219a19a1736a7b84c64f4c6ee69a61446aa9099f Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Tue, 1 Oct 2024 21:33:14 +0200 Subject: [PATCH] [add] widget system (to be outsourced to plankton) [add] widget:sources [add] widget:weekview [mod] page:events:make use of new widgets --- data/example.kal.json | 347 ------- source/data/localization/deu.loc.json | 10 +- source/data/localization/eng.loc.json | 10 +- source/logic/backend.ts | 24 +- source/logic/view.ts | 791 ---------------- source/logic/widget.ts | 18 + source/pages/event_add/logic.ts | 6 +- source/pages/events/logic.ts | 270 ++---- .../pages/events/templates/default.html.tpl | 6 + source/pages/events/templates/events.html.tpl | 19 - .../tableview-sources-entry.html.tpl | 1 - source/style/common.css | 73 ++ source/style/main.css | 174 +--- source/style/pages.css | 43 + source/style/plankton.css | 25 + source/style/widgets.css | 26 + source/widgets/sources/logic.ts | 123 +++ .../widgets/sources/templates/entry.html.tpl | 1 + .../widgets/sources/templates/main.html.tpl | 3 + source/widgets/weekview/logic.ts | 875 ++++++++++++++++++ .../weekview/templates/main.html.tpl} | 23 +- .../templates/tableview-cell-entry.html.tpl | 0 .../templates/tableview-cell.html.tpl | 0 .../templates/tableview-row.html.tpl | 0 tools/makefile | 20 +- 25 files changed, 1376 insertions(+), 1512 deletions(-) delete mode 100644 data/example.kal.json delete mode 100644 source/logic/view.ts create mode 100644 source/logic/widget.ts create mode 100644 source/pages/events/templates/default.html.tpl delete mode 100644 source/pages/events/templates/events.html.tpl delete mode 100644 source/pages/events/templates/tableview-sources-entry.html.tpl create mode 100644 source/style/common.css create mode 100644 source/style/pages.css create mode 100644 source/style/plankton.css create mode 100644 source/style/widgets.css create mode 100644 source/widgets/sources/logic.ts create mode 100644 source/widgets/sources/templates/entry.html.tpl create mode 100644 source/widgets/sources/templates/main.html.tpl create mode 100644 source/widgets/weekview/logic.ts rename source/{pages/events/templates/tableview.html.tpl => widgets/weekview/templates/main.html.tpl} (51%) rename source/{pages/events => widgets/weekview}/templates/tableview-cell-entry.html.tpl (100%) rename source/{pages/events => widgets/weekview}/templates/tableview-cell.html.tpl (100%) rename source/{pages/events => widgets/weekview}/templates/tableview-row.html.tpl (100%) diff --git a/data/example.kal.json b/data/example.kal.json deleted file mode 100644 index e0b12aa..0000000 --- a/data/example.kal.json +++ /dev/null @@ -1,347 +0,0 @@ -{ - "users": [ - { - "id": 1, - "object": { - "name": "christian.frass" - } - }, - { - "id": 2, - "object": { - "name": "andre.weichert" - } - }, - { - "id": 3, - "object": { - "name": "steffen.doegnitz" - } - }, - { - "id": 4, - "object": { - "name": "frank.dietrich" - } - }, - { - "id": 5, - "object": { - "name": "michael.berger" - } - }, - { - "id": 6, - "object": { - "name": "roland.schroeder" - } - }, - { - "id": 7, - "object": { - "name": "rene.hahn" - } - }, - { - "id": 8, - "object": { - "name": "max.meierhof" - } - }, - { - "id": 9, - "object": { - "name": "klaus.kleba" - } - }, - { - "id": 10, - "object": { - "name": "tim.detzner" - } - } - ], - "calendars": [ - { - "id": 1, - "object": { - "kind": "concrete", - "data": { - "name": "BV", - "private": false, - "hue": 0.0000000000000000, - "users": [ - ], - "events": [ - { - "name": "9. Bundesparteitag | 1. Sitzung | Tag 1", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 18}, - "time": {"hour": 10, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 18}, - "time": {"hour": 18, "minute": 0, "second": 0} - }, - "location": "Halle", - "description": null - }, - { - "name": "9. Bundesparteitag | 1. Sitzung | Tag 2", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 19}, - "time": {"hour": 10, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 19}, - "time": {"hour": 18, "minute": 0, "second": 0} - }, - "location": "Halle", - "description": null - }, - { - "name": "9. Bundesparteitag | 1. Sitzung | Tag 3", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 20}, - "time": {"hour": 10, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 10, "day": 20}, - "time": {"hour": 18, "minute": 0, "second": 0} - }, - "location": "Halle", - "description": null - } - ] - } - } - }, - { - "id": 2, - "object": { - "kind": "concrete", - "data": { - "name": "LV Sachsen", - "private": false, - "hue": 0.6180339887498949, - "users": [ - { - "id": 9, - "role": "editor" - } - ], - "events": [ - { - "name": "Sören Pellmann zu den Landtagswahlen im Osten", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 11}, - "time": {"hour": 18, "minute": 0, "second": 0} - }, - "end": null, - "location": "online: https://v2202002113208108062.supersrv.de/b/har-jbu-lxy-rx1", - "description": null - }, - { - "name": "Erinnern versammeln. Praktiken für die Zukünfte einer Gesellschaft der Vielen.", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 13}, - "time": {"hour": 17, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 15}, - "time": null - }, - "location": "Weltecho, Annaberger Straße 24, 09111 Chemnitz", - "description": null - }, - { - "name": "Parteikonvent zur Auswertung des Wahljahres", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 14}, - "time": {"hour": 10, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 14}, - "time": {"hour": 16, "minute": 30, "second": 0} - }, - "location": "Veranstaltungs- und Kulturforum STADTPARK | Hammertal 3 | 09669 Frankenberg/Sachsen", - "description": null - }, - { - "name": "Ist die extreme Rechte noch zu stoppen?", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 19}, - "time": {"hour": 19, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 19}, - "time": {"hour": 21, "minute": 0, "second": 0} - }, - "location": "online: https://www.dielinke-sachsen.de/termine/?termin_ort=digital-internet-stream", - "description": null - } - ] - } - } - }, - { - "id": 3, - "object": { - "kind": "concrete", - "data": { - "name": "KV Zwickau", - "private": false, - "hue": 0.4721359549995796, - "events": [ - { - "name": "Vorstands-Sitzung", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 5}, - "time": {"hour": 18, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 5}, - "time": {"hour": 21, "minute": 0, "second": 0} - }, - "location": "Zwickau, Innere Schneeberger Straße 17", - "description": null - } - ] - } - } - }, - { - "id": 4, - "object": { - "kind": "concrete", - "data": { - "name": "OV Glauchau", - "private": false, - "users": [ - { - "id": 1, - "role": "editor" - }, - { - "id": 5, - "role": "editor" - }, - { - "id": 6, - "role": "editor" - } - ], - "hue": 0.09016994374947451, - "events": [ - { - "name": "Kinderspieletag", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 8}, - "time": {"hour": 12, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 8}, - "time": {"hour": 16, "minute": 0, "second": 0} - }, - "location": null, - "description": null - }, - { - "name": "Mitglieder-Sitzung", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 19}, - "time": {"hour": 17, "minute": 30, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 19}, - "time": {"hour": 19, "minute": 0, "second": 0} - }, - "location": null, - "description": null - } - ] - } - } - }, - { - "id": 5, - "object": { - "kind": "concrete", - "data": { - "name": "OV Zwickau", - "private": false, - "hue": 0.09016994374947451, - "users": [ - { - "id": 7, - "role": "editor" - }, - { - "id": 8, - "role": "viewer" - } - ], - "events": [ - { - "name": "4ter Christopher Street Day", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 8, "day": 31}, - "time": {"hour": 10, "minute": 0, "second": 0} - }, - "end": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 8, "day": 31}, - "time": {"hour": 17, "minute": 0, "second": 0} - }, - "location": "Zwickau", - "description": null - }, - { - "name": "Regionaltreffen Westsachsen: Schule ohne Rassismus – Schule mit Courage", - "begin": { - "timezone_shift": 2, - "date": {"year": 2024, "month": 9, "day": 19}, - "time": {"hour": 9, "minute": 0, "second": 0} - }, - "end": null, - "location": null, - "description": null - } - ] - } - } - }, - { - "id": 6, - "object": { - "kind": "caldav", - "data": { - "name": "Lixer", - "private": true, - "read_only": true, - "source_url": "https://export.kalender.digital/ics/0/3e10dae66950379d4cc8/gesamterkalender.ics?past_months=3&future_months=36" - } - } - } - ] -} diff --git a/source/data/localization/deu.loc.json b/source/data/localization/deu.loc.json index c444bc2..cd8a675 100644 --- a/source/data/localization/deu.loc.json +++ b/source/data/localization/deu.loc.json @@ -28,6 +28,10 @@ "calendar.access.access": "Zugriff", "calendar.access.default_level": "Standard", "calendar.access.attributed": "Zuweisungen", + "widget.weekview.controls.year": "Jahr", + "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", @@ -46,10 +50,6 @@ "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.events.controls.year": "Jahr", - "page.events.controls.week": "Woche", - "page.events.controls.count": "Anzahl", - "page.events.controls.apply": "Laden" + "page.event_edit.actions.remove": "löschen" } } diff --git a/source/data/localization/eng.loc.json b/source/data/localization/eng.loc.json index 2fd3faf..1253c3b 100644 --- a/source/data/localization/eng.loc.json +++ b/source/data/localization/eng.loc.json @@ -28,6 +28,10 @@ "calendar.access.access": "access", "calendar.access.default_level": "default", "calendar.access.attributed": "attributed", + "widget.weekview.controls.year": "Year", + "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", @@ -46,10 +50,6 @@ "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.events.controls.year": "Year", - "page.events.controls.week": "Week", - "page.events.controls.count": "Count", - "page.events.controls.apply": "Load" + "page.event_edit.actions.remove": "delete" } } diff --git a/source/logic/backend.ts b/source/logic/backend.ts index 7491fc3..9c67e9f 100644 --- a/source/logic/backend.ts +++ b/source/logic/backend.ts @@ -257,15 +257,29 @@ namespace _zeitbild.frontend_web.backend { id : int; name : string; - access_level : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; } > > { - return call( - lib_plankton.http.enum_method.get, - "/calendar", - null + return ( + call( + lib_plankton.http.enum_method.get, + "/calendar", + null + ) + .then( + (entries) => Promise.resolve( + entries + .map( + (entry) => ({ + "id": entry.id, + "name": entry.name, + "access_level": access_level_decode(entry.access_level), + }) + ) + ) + ) ); } diff --git a/source/logic/view.ts b/source/logic/view.ts deleted file mode 100644 index 0d0414c..0000000 --- a/source/logic/view.ts +++ /dev/null @@ -1,791 +0,0 @@ - -/** - */ -namespace _zeitbild.frontend_web.view -{ - - /** - */ - function event_generate_tooltip( - calendar_name : string, - event : _zeitbild.frontend_web.type.event_object - ) : string - { - return ( - lib_plankton.string.coin( - "[{{calendar_name}}] {{event_name}}\n", - { - "calendar_name": calendar_name, - "event_name": event.name, - } - ) - + - "--\n" - + - ( - (event.begin.time !== null) - ? - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Anfang", // TODO: translate - "value": lib_plankton.string.coin( - "{{hour}}:{{minute}}", - { - "hour": event.begin.time.hour.toFixed(0).padStart(2, "0"), - "minute": event.begin.time.minute.toFixed(0).padStart(2, "0"), - } - ), // TODO: outsource - } - ) - : - "" - ) - + - ( - (event.end !== null) - ? - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Ende", // TODO: translate - "value": ( - [ - ( - ( - (event.end.date.year !== event.begin.date.year) - || - (event.end.date.month !== event.begin.date.month) - || - (event.end.date.day !== event.begin.date.day) - ) - ? - lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": event.end.date.year.toFixed(0).padStart(4, "0"), - "month": event.end.date.month.toFixed(0).padStart(2, "0"), - "day": event.end.date.day.toFixed(0).padStart(2, "0"), - } - ) - : - null - ), - ( - (event.end.time !== null) - ? - lib_plankton.string.coin( - "{{hour}}:{{minute}}", - { - "hour": event.end.time.hour.toFixed(0).padStart(2, "0"), - "minute": event.end.time.minute.toFixed(0).padStart(2, "0"), - } - ) - : - null - ), - ] - .filter(x => (x !== null)) - .join(",") - ), - } - ) - : - "" - ) - + - ( - (event.location !== null) - ? - ( - lib_plankton.string.coin( - "{{label}}: {{value}}\n", - { - "label": "Ort", // TODO - "value": event.location, - } - ) - ) - : - "" - ) - + - ( - (event.description !== null) - ? - ( - "--\n" - + - lib_plankton.string.coin( - "{{description}}\n", - { - "description": event.description, - } - ) - ) - : - "" - ) - ); - } - - - /** - * @todo kein "while" - */ - async function calendar_view_table_data( - calendar_ids : ( - null - | - Array<_zeitbild.frontend_web.type.calendar_id> - ), - from : { - year : int; - week : int; - }, - to : { - year : int; - week : int; - }, - timezone_shift : int, - ) : Promise< - { - sources : lib_plankton.map.type_map< - _zeitbild.frontend_web.type.calendar_id, - { - name : string; - access_level : _zeitbild.frontend_web.type.enum_access_level; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - >; - today : boolean; - } - >; - } - > - } - > - { - const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); - const from_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( - { - "year": (from as {year : int; week : int}).year, - "week": (from as {year : int; week : int}).week, - "day": 1, - }, - { - "timezone_shift": (timezone_shift as int), - } - ); - const to_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( - { - "year": (to as {year : int; week : int}).year, - "week": (to as {year : int; week : int}).week, - "day": 1, - }, - { - "timezone_shift": (timezone_shift as int), - } - ); - - // prepare - const entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - calendar_name : string; - access_level : _zeitbild.frontend_web.type.enum_access_level; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - > = await _zeitbild.frontend_web.backend.events( - from_pit, - to_pit, - { - "calendar_ids": calendar_ids, - } - ); - let result : { - sources : lib_plankton.map.type_map< - _zeitbild.frontend_web.type.calendar_id, - { - name : string; - access_level : _zeitbild.frontend_web.type.enum_access_level; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - >; - today : boolean; - } - >; - } - >; - } = { - "sources": lib_plankton.map.hashmap.implementation_map( - lib_plankton.map.hashmap.make( - x => x.toFixed(0), - { - "pairs": ( - entries - .map( - (entry) => ( - { - "key": entry.calendar_id, - "value": { - "name": entry.calendar_name, - "access_level": entry.access_level, - } - } - ) - ) - ) - } - ) - ), - "rows": [], - }; - let row : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - >; - today : boolean; - } - > = []; - let day : int = 0; - while (true) { - const pit_current : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day( - from_pit, - day - ); - if ( - lib_plankton.pit.is_before( - pit_current, - to_pit - ) - ) { - day += 1; - row.push( - { - "pit": pit_current, - "entries": [], - "today": false, // TODO - } - ); - if (day % 7 === 0) { - result.rows.push( - { - "week": ( - (from as {year : int; week : int}).week - + - Math.floor(day / 7) - - - 1 // TODO - ), - "data": row - } - ); - row = []; - } - else { - // do nothing - } - } - else { - break; - } - } - - // fill - { - // events - ( - entries - .forEach( - (entry) => { - const distance_seconds : int = ( - lib_plankton.pit.from_datetime(entry.event_object.begin) - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].entries.push(entry); - } - else { - // do nothing - } - } - ) - ); - // today - { - const distance_seconds : int = ( - now_pit - - - from_pit - ); - const distance_days : int = (distance_seconds / (60 * 60 * 24)); - - const week : int = Math.floor(Math.floor(distance_days) / 7); - const day : int = (Math.floor(distance_days) % 7); - - if ((week >= 0) && (week < result.rows.length)) { - result.rows[week].data[day].today = true; - } - else { - // do nothing - } - } - } - - return Promise.resolve(result); - } - - - /** - */ - export async function calendar_view_table_html( - options : { - calendar_ids ?: ( - null - | - Array<_zeitbild.frontend_web.type.calendar_id> - ); - from ?: { - year : int; - week : int; - }; - to ?: { - year : int; - week : int; - }; - timezone_shift ?: int; - action_select ?: ( - ( - calendar_id : _zeitbild.frontend_web.type.calendar_id, - event_id : _zeitbild.frontend_web.type.local_resource_event_id - ) - => - void - ) - } = {} - ) : Promise - { - const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); - options = Object.assign( - { - "calendar_ids": null, - "from": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, -1), - lib_plankton.pit.to_ywd, - x => ({"year": x.year, "week": x.week}), - ] - ), - "to": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, +4), - lib_plankton.pit.to_ywd, - x => ({"year": x.year, "week": x.week}), - ] - ), - "timezone_shift": 0, - }, - options - ); - const stuff : { - sources : lib_plankton.map.type_map< - _zeitbild.frontend_web.type.calendar_id, - { - name : string; - access_level : _zeitbild.frontend_web.type.enum_access_level; - } - >; - rows : Array< - { - week : int; - data : Array< - { - pit : lib_plankton.pit.type_pit; - entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - >; - today : boolean; - } - >; - } - >; - } = await calendar_view_table_data( - options.calendar_ids, - options.from, - options.to, - options.timezone_shift - ); - const sources : lib_plankton.map.type_map< - _zeitbild.frontend_web.type.calendar_id, - { - name : string; - access_level : _zeitbild.frontend_web.type.enum_access_level; - color : lib_plankton.color.type_color; - } - > = lib_plankton.map.hashmap.implementation_map( - lib_plankton.map.hashmap.make( - (x => x.toFixed(0)), - { - "pairs": ( - lib_plankton.map.dump( - stuff.sources - ) - .map( - (pair) => ({ - "key": pair.key, - "value": { - "name": pair.value.name, - "access_level": pair.value.access_level, - "color": lib_plankton.color.give_generic( - (pair.key - 1), - { - "saturation": 0.375, - "value": 0.375, - } - ), - } - }) - ) - ) - } - ) - ); - return _zeitbild.frontend_web.helpers.template_coin( - "events", - "tableview", - { - "sources": ( - await _zeitbild.frontend_web.helpers.promise_row( - lib_plankton.map.dump(sources) - .map( - ({"key": calendar_id, "value": data}) => async () => _zeitbild.frontend_web.helpers.template_coin( - "events", - "tableview-sources-entry", - { - "name": data.name, - // "access_level": data.access_level, - "color": lib_plankton.color.output_hex(data.color), - "rel": calendar_id.toFixed(0), - } - ) - ) - ) - ).join(""), - "rows": ( - await _zeitbild.frontend_web.helpers.promise_row( - stuff.rows - .map( - (row) => async () => _zeitbild.frontend_web.helpers.template_coin( - "events", - "tableview-row", - { - "week": row.week.toFixed(0).padStart(2, "0"), - "cells": ( - await _zeitbild.frontend_web.helpers.promise_row( - row.data - .map( - (cell) => async () => _zeitbild.frontend_web.helpers.template_coin( - "events", - "tableview-cell", - { - "extra_classes": ( - [""] - .concat(cell.today ? ["calendar-cell-today"] : []) - .join(" ") - ), - "title": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "day": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ), - ] - ), - "rel": lib_plankton.call.convey( - cell.pit, - [ - lib_plankton.pit.to_datetime, - (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( - "{{year}}-{{month}}-{{day}}", - { - "year": x.date.year.toFixed(0).padStart(4, "0"), - "month": x.date.month.toFixed(0).padStart(2, "0"), - "day": x.date.day.toFixed(0).padStart(2, "0"), - } - ) - ] - ), - "entries": ( - await _zeitbild.frontend_web.helpers.promise_row( - cell.entries - .map( - (entry) => () => _zeitbild.frontend_web.helpers.template_coin( - "events", - "tableview-cell-entry", - { - "color": lib_plankton.color.output_hex( - sources.get( - entry.calendar_id - ).color - ), - "title": event_generate_tooltip( - sources.get( - entry.calendar_id - ).name, - entry.event_object - ), - "name": entry.event_object.name, - "rel": lib_plankton.string.coin( - "{{calendar_id}}/{{event_id}}/{{access_level}}", - { - "calendar_id": entry.calendar_id.toFixed(0), - "event_id": ( - (entry.event_id === null) - ? - "-" - : - entry.event_id.toFixed(0) - ), - "access_level": (() => { - const access_level : _zeitbild.frontend_web.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) { - case _zeitbild.frontend_web.type.enum_access_level.none: return "none"; - case _zeitbild.frontend_web.type.enum_access_level.view: return "view"; - case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit"; - case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - "additional_classes": lib_plankton.string.coin( - " access_level-{{access_level}}", - { - "access_level": (() => { - const access_level : _zeitbild.frontend_web.type.enum_access_level = sources.get(entry.calendar_id).access_level; - switch (access_level) { - case _zeitbild.frontend_web.type.enum_access_level.none: return "none"; - case _zeitbild.frontend_web.type.enum_access_level.view: return "view"; - case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit"; - case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin"; - } - }) (), - } - ), - } - ) - ) - ) - ).join(""), - } - ) - ) - ) - ).join(""), - } - ) - ) - ) - ).join(""), - } - ); - } - - - /** - */ - async function calendar_view_list_data( - calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id>, - options : { - from ?: lib_plankton.pit.type_pit; - to ?: lib_plankton.pit.type_pit; - timezone_shift ?: int; - } = {} - ) : Promise< - Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - > - > - { - const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); - options = Object.assign( - { - "from": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_day(x, -1), - ] - ), - "to": lib_plankton.call.convey( - now_pit, - [ - (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, +4), - ] - ), - "timezone_shift": 0, - }, - options - ); - - const entries : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - > = await _zeitbild.frontend_web.backend.events( - (options.from as lib_plankton.pit.type_pit), - (options.to as lib_plankton.pit.type_pit), - { - "calendar_ids": calendar_ids, - } - ); - // TODO: optimize - entries.sort( - (entry_1, entry_2) => ( - lib_plankton.pit.from_datetime(entry_1.event_object.begin) - - - lib_plankton.pit.from_datetime(entry_2.event_object.begin) - ) - ); - - return Promise.resolve(entries); - } - - - /** - */ - export async function calendar_view_list_html( - calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id>, - options : { - from ?: lib_plankton.pit.type_pit; - to ?: lib_plankton.pit.type_pit; - timezone_shift ?: int; - } = {} - ) : Promise - { - const stuff : Array< - { - calendar_id : _zeitbild.frontend_web.type.calendar_id; - event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); - event_object : _zeitbild.frontend_web.type.event_object; - } - > = await calendar_view_list_data( - calendar_ids, - options - ); - return Promise.resolve( - new lib_plankton.xml.class_node_complex( - "div", - { - "class": "list", - }, - [ - new lib_plankton.xml.class_node_complex( - "style", - {}, - [ - new lib_plankton.xml.class_node_text( - "html {background-color: #111; color: #FFF; font-family: sans-serif;}\n" - + - "table {width: 100%; border-collapse: collapse;}\n" - ) - ] - ), - new lib_plankton.xml.class_node_complex( - "ul", - { - "class": "list-events", - }, - ( - stuff - .map( - (entry) => ( - new lib_plankton.xml.class_node_complex( - "li", - { - "class": "list-event_entry", - }, - [ - new lib_plankton.xml.class_node_text( - JSON.stringify(entry) - ), - ] - ) - ) - ) - ) - ), - ] - ).compile() - ); - } - -} diff --git a/source/logic/widget.ts b/source/logic/widget.ts new file mode 100644 index 0000000..9e7542b --- /dev/null +++ b/source/logic/widget.ts @@ -0,0 +1,18 @@ +namespace _zeitbild +{ + + /** + * @todo outsource + */ + export abstract class class_widget + { + + /** + */ + public abstract load( + target_element : Element + ) : Promise; + + } + +} diff --git a/source/pages/event_add/logic.ts b/source/pages/event_add/logic.ts index dc36376..33892af 100644 --- a/source/pages/event_add/logic.ts +++ b/source/pages/event_add/logic.ts @@ -112,7 +112,11 @@ namespace _zeitbild.frontend_web.pages ( (await _zeitbild.frontend_web.backend.calendar_list()) .filter( - (entry) => (["edit","admin"].includes(entry.access_level)) + (entry) => ( + (entry.access_level === _zeitbild.frontend_web.type.enum_access_level.edit) + || + (entry.access_level === _zeitbild.frontend_web.type.enum_access_level.admin) + ) ) .map( (entry) => ({ diff --git a/source/pages/events/logic.ts b/source/pages/events/logic.ts index f2e85fa..c1b1561 100644 --- a/source/pages/events/logic.ts +++ b/source/pages/events/logic.ts @@ -1,4 +1,4 @@ -namespace _zeitbild.frontend_web.pages +namespace _zeitbild.frontend_web.pages.events { /** @@ -6,183 +6,117 @@ namespace _zeitbild.frontend_web.pages lib_plankton.zoo_page.register( "events", async (parameters, target_element) => { - const load = async function (year, week, count) { - // controls - { - (target_element.querySelector("#events_control_year > input") as HTMLInputElement).value = year.toFixed(0); - (target_element.querySelector("#events_control_week > input") as HTMLInputElement).value = week.toFixed(0); - (target_element.querySelector("#events_control_count > input") as HTMLInputElement).value = count.toFixed(0); - } - // table - { - target_element.querySelector("#events_table").innerHTML = await _zeitbild.frontend_web.view.calendar_view_table_html( - { - "calendar_ids": null, - // TODO - "from": { - "year": year, - "week": week - }, - // TODO - "to": { - "year": year, - "week": (week + count) - }, - "timezone_shift": /*conf.timezone_shift*/0, - } - ); - // sources - { - target_element.querySelectorAll(".tableview-sources-entry").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - const calendar_id : _zeitbild.frontend_web.type.calendar_id = parseInt(element.getAttribute("rel")); - lib_plankton.zoo_page.set( - { - "name": "calendar_edit", - "parameters": { - "read_only": false, // TODO - "calendar_id": calendar_id, - } - } - ); - } - ); - } - ); - } - // cells - { - target_element.querySelectorAll(".calendar-cell-regular").forEach( - (element) => { - element.addEventListener( - "click", - (event) => { - if (! (element === event.target)) { - // do nothing - } - else { - const rel : string = element.getAttribute("rel"); - const parts : Array = rel.split("-"); - const year : int = parseInt(parts[0]); - const month : int = parseInt(parts[1]); - const day : int = parseInt(parts[2]); - lib_plankton.zoo_page.set( - { - "name": "event_add", - "parameters": { - "calendar_id": null, - "year": year, - "month": month, - "day": day, - } - } - ); - } - } - ); - } - ); - } - // events - { - target_element.querySelectorAll(".calendar-event_entry").forEach( - (element) => { - element.addEventListener( - "click", - () => { - const rel : string = element.getAttribute("rel"); - const parts : Array = rel.split("/"); - const calendar_id : _zeitbild.frontend_web.type.calendar_id = parseInt(parts[0]); - const event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id) = ( - (parts[1] === "-") - ? - null - : - parseInt(parts[1]) - ); - const access_level : _zeitbild.frontend_web.type.enum_access_level = (() => { - switch (parts[2]) { - case "none": return _zeitbild.frontend_web.type.enum_access_level.none; - case "view": return _zeitbild.frontend_web.type.enum_access_level.view; - case "edit": return _zeitbild.frontend_web.type.enum_access_level.edit; - case "admin": return _zeitbild.frontend_web.type.enum_access_level.admin; - } - }) (); - switch (access_level) { - case _zeitbild.frontend_web.type.enum_access_level.none: { - throw (new Error("this event should not be visible")); - break; - } - case _zeitbild.frontend_web.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, - } - } - ); - break; - } - case _zeitbild.frontend_web.type.enum_access_level.edit: - case _zeitbild.frontend_web.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, - } - } - ); - break; - } - } - } - ); - } - ); - } - } - }; - - target_element.innerHTML = ""; target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin( "events", - "events", + "default", { - "label_control_year": lib_plankton.translate.get("page.events.controls.year"), - "label_control_week": lib_plankton.translate.get("page.events.controls.week"), - "label_control_count": lib_plankton.translate.get("page.events.controls.count"), - "label_control_apply": lib_plankton.translate.get("page.events.controls.apply"), } ); - // controls + // sources { - target_element.querySelector("#events_control_apply").addEventListener( - "click", - (event) => { - event.preventDefault(); - const year : int = parseInt((target_element.querySelector("#events_control_year > input") as HTMLInputElement).value); - const week : int = parseInt((target_element.querySelector("#events_control_week > input") as HTMLInputElement).value); - const count : int = parseInt((target_element.querySelector("#events_control_count > input") as HTMLInputElement).value); - load(year, week, count); + const data : Array< + { + id : _zeitbild.frontend_web.type.calendar_id; + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + } + > = await _zeitbild.frontend_web.backend.calendar_list( + ); + const widget_sources = new _zeitbild.frontend_web.widgets.sources.class_widget_sources( + data, + { + "action_select": (entry) => { + switch (entry.access_level) { + case _zeitbild.frontend_web.type.enum_access_level.none: { + throw (new Error("this event should not be visible")); + break; + } + case _zeitbild.frontend_web.type.enum_access_level.edit: + case _zeitbild.frontend_web.type.enum_access_level.view: { + lib_plankton.zoo_page.set( + { + "name": "calendar_edit", + "parameters": { + "read_only": "yes", + "calendar_id": entry.id, + } + } + ); + break; + } + case _zeitbild.frontend_web.type.enum_access_level.admin: { + lib_plankton.zoo_page.set( + { + "name": "calendar_edit", + "parameters": { + "read_only": "no", + "calendar_id": entry.id, + } + } + ); + break; + } + } + }, } ); + await widget_sources.load(target_element.querySelector("#events-pane-left")); } - // table + // weekview { - const ywd_now : lib_plankton.pit.type_ywd = lib_plankton.pit.to_ywd(lib_plankton.pit.now()); - let year : int = ywd_now.year; - let week : int = Math.max(0, (ywd_now.week - 1)); - let count : int = 5; - load(year, week, count); + const widget_weekview = new _zeitbild.frontend_web.widgets.weekview.class_widget_weekview( + { + "action_select_day": (date) => { + lib_plankton.zoo_page.set( + { + "name": "event_add", + "parameters": { + "calendar_id": null, + "year": date.year, + "month": date.month, + "day": date.day, + } + } + ); + }, + "action_select_event": (calendar_id, access_level, event_id) => { + switch (access_level) { + case _zeitbild.frontend_web.type.enum_access_level.none: { + throw (new Error("this event should not be visible")); + break; + } + case _zeitbild.frontend_web.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, + } + } + ); + break; + } + case _zeitbild.frontend_web.type.enum_access_level.edit: + case _zeitbild.frontend_web.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, + } + } + ); + break; + } + } + } + } + ); + await widget_weekview.load(target_element.querySelector("#events-pane-right")); } return Promise.resolve(undefined); }, diff --git a/source/pages/events/templates/default.html.tpl b/source/pages/events/templates/default.html.tpl new file mode 100644 index 0000000..8138a97 --- /dev/null +++ b/source/pages/events/templates/default.html.tpl @@ -0,0 +1,6 @@ +
+
+
+
+
+
diff --git a/source/pages/events/templates/events.html.tpl b/source/pages/events/templates/events.html.tpl deleted file mode 100644 index b5be00f..0000000 --- a/source/pages/events/templates/events.html.tpl +++ /dev/null @@ -1,19 +0,0 @@ -
-
- - - - -
-
-
-
diff --git a/source/pages/events/templates/tableview-sources-entry.html.tpl b/source/pages/events/templates/tableview-sources-entry.html.tpl deleted file mode 100644 index 861ea42..0000000 --- a/source/pages/events/templates/tableview-sources-entry.html.tpl +++ /dev/null @@ -1 +0,0 @@ -
  • {{name}}
  • diff --git a/source/style/common.css b/source/style/common.css new file mode 100644 index 0000000..5b051a7 --- /dev/null +++ b/source/style/common.css @@ -0,0 +1,73 @@ +.tableview-sources-entry:not(.tableview-sources-entry-active) +{ + filter: saturate(0); +} + +.calendar-cell +{ + border: 1px solid hsl(0,0%,37.5%); + padding: 8px; + vertical-align: top; +} + +.calendar-cell-day +{ + width: 13.5%; +} + +.calendar-cell-week +{ + width: 5.5%; +} + +.calendar-cell-regular +{ + width: 13.5%; + height: 120px; + + cursor: copy; +} + +.calendar-cell-today +{ + outline: 2px solid hsl(0, 0%, 100%); +} + +.calendar-day +{ + font-size: 0.75em; + cursor: help; +} + +.calendar-events +{ + margin: 0; padding: 0; + list-style-type: none; +} + +.calendar-event_entry +{ + margin: 4px; + padding: 4px; + border-radius: 2px; + font-size: 0.75em; + color: #FFF; + font-weight: bold; +} + +.calendar-event_entry.access_level-none +, +.calendar-event_entry.access_level-view +{ + /* + cursor: default; + */ + cursor: pointer; +} + +.calendar-event_entry.access_level-edit +, +.calendar-event_entry.access_level-admin +{ + cursor: pointer; +} diff --git a/source/style/main.css b/source/style/main.css index 3a6b404..ed3cb94 100644 --- a/source/style/main.css +++ b/source/style/main.css @@ -1,10 +1,12 @@ -html { +html +{ background-color: hsl(0, 0%, 12.5%); color: hsl(0, 0%, 100%); font-family: sans-serif; } -header { +header +{ background-color: hsl(0, 0%, 25%); /* border-bottom: 2px solid #888; @@ -13,25 +15,29 @@ header { margin-bottom: 16px; } -nav > ul { +nav > ul +{ list-style-type: none; margin: 0; padding: 0; } -nav > ul > li { +nav > ul > li +{ display: inline-block; margin: 8px; padding: 8px; } -a { +a +{ padding: 8px; text-decoration: none; color: hsl(0, 0%, 87.5%); } -a:hover { +a:hover +{ color: hsl(0, 0%, 100%); border-bottom: 2px solid hsl(0, 0%, 100%); transition: 1s ease color; @@ -57,159 +63,3 @@ input,select,button margin: 4px; border-radius: 2px; } - -.calendar { - display: flex; - flex-direction: row; - flex-wrap: wrap; -} - -.calendar-pane-left { - flex-basis: 12.5%; -} - -.calendar-pane-right { - flex-basis: 87.5%; -} - -.tableview-sources { - margin: 0; - padding: 0; - list-style-type: none; - font-size: 0.75em; -} - -.tableview-sources-entry { - margin: 8px; - padding: 4px; - cursor: pointer; -} - -.tableview-sources-entry:not(.tableview-sources-entry-active) { - filter: saturate(0); -} - -.calendar table { - width: 100%; - border-collapse: collapse; -} - -.calendar-cell { - border: 1px solid hsl(0,0%,37.5%); - padding: 8px; - vertical-align: top; -} - -.calendar-cell-day { - width: 13.5%; -} - -.calendar-cell-week { - width: 5.5%; -} - -.calendar-cell-regular { - width: 13.5%; - height: 120px; - - cursor: copy; -} - -.calendar-cell-today { - outline: 2px solid hsl(0, 0%, 100%); -} - -.calendar-day { - font-size: 0.75em; - cursor: help; -} - -.calendar-events { - margin: 0; padding: 0; - list-style-type: none; -} - -.calendar-event_entry { - margin: 4px; - padding: 4px; - border-radius: 2px; - font-size: 0.75em; - color: #FFF; - font-weight: bold; -} - -.calendar-event_entry.access_level-none -, -.calendar-event_entry.access_level-view -{ - /* - cursor: default; - */ - cursor: pointer; -} - -.calendar-event_entry.access_level-edit -, -.calendar-event_entry.access_level-admin -{ - cursor: pointer; -} - -.plankton_input_group_field { - margin-bottom: 8px; -} - -.plankton_input_group_field_label { - display: block; - font-weight: bold; - font-size: 0.8em; -} - -.plankton_input_soft_container > * { - display: inline-block; -} - -.plankton_input_soft_setter { - margin-right: 8px; -} - -.plankton_input_soft_inactive { - display: none !important; -} - -.plankton_input_group { - margin-left: 24px; -} - -#events_controls { - margin-bottom: 12px; - text-align: center; -} - - -#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; -} - -#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 -, -#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; -} diff --git a/source/style/pages.css b/source/style/pages.css new file mode 100644 index 0000000..96531d0 --- /dev/null +++ b/source/style/pages.css @@ -0,0 +1,43 @@ +#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; +} + +#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 +, +#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; +} + +#events +{ + display: flex; + flex-direction: row; + flex-wrap: wrap; +} + +#events-pane-left +{ + flex-basis: 12.5%; +} + +#events-pane-right +{ + flex-basis: 87.5%; +} diff --git a/source/style/plankton.css b/source/style/plankton.css new file mode 100644 index 0000000..e101aa2 --- /dev/null +++ b/source/style/plankton.css @@ -0,0 +1,25 @@ +.plankton_input_group_field { + margin-bottom: 8px; +} + +.plankton_input_group_field_label { + display: block; + font-weight: bold; + font-size: 0.8em; +} + +.plankton_input_soft_container > * { + display: inline-block; +} + +.plankton_input_soft_setter { + margin-right: 8px; +} + +.plankton_input_soft_inactive { + display: none !important; +} + +.plankton_input_group { + margin-left: 24px; +} diff --git a/source/style/widgets.css b/source/style/widgets.css new file mode 100644 index 0000000..207474f --- /dev/null +++ b/source/style/widgets.css @@ -0,0 +1,26 @@ +.sources +{ + margin: 0; + padding: 0; + list-style-type: none; + font-size: 0.75em; +} + +.sources-entry +{ + margin: 8px; + padding: 4px; + cursor: pointer; +} + +.weekview-controls +{ + margin-bottom: 12px; + text-align: center; +} + +.weekview-table table +{ + width: 100%; + border-collapse: collapse; +} diff --git a/source/widgets/sources/logic.ts b/source/widgets/sources/logic.ts new file mode 100644 index 0000000..934cc5e --- /dev/null +++ b/source/widgets/sources/logic.ts @@ -0,0 +1,123 @@ +namespace _zeitbild.frontend_web.widgets.sources +{ + + /** + */ + type type_entry = { + id : _zeitbild.frontend_web.type.calendar_id; + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + }; + + + /** + */ + export class class_widget_sources extends _zeitbild.class_widget + { + + /** + */ + private keys : Array; + + + /** + */ + private data : Record; + + + /** + */ + private action_select : ((entry : type_entry) => void); + + + /** + */ + public constructor( + entries : Array, + options : { + action_select ?: ((entry : type_entry) => void); + } = {} + ) + { + options = Object.assign( + { + "action_select": (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_select = options.action_select; + } + + + /** + * [implementation] + */ + public async load( + target_element : Element + ) : Promise + { + target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin( + "widget-sources", + "main", + { + "entries": ( + ( + await _zeitbild.frontend_web.helpers.promise_row( + this.keys + .map( + (key) => () => { + const entry : type_entry = this.data[key]; + return _zeitbild.frontend_web.helpers.template_coin( + "widget-sources", + "entry", + { + "name": entry.name, + // "access_level": entry.access_level, // TODO + "color": lib_plankton.color.output_hex( + lib_plankton.color.give_generic( + (entry.id - 1), + { + "saturation": 0.375, + "value": 0.375, + } + ), + ), + "rel": key, + } + ); + } + ) + ) + ) + .join("") + ), + } + ); + target_element.querySelectorAll(".sources-entry").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + const key : string = element.getAttribute("rel"); + const entry : type_entry = this.data[key]; + this.action_select(entry); + } + ); + } + ); + return Promise.resolve(undefined); + } + + } + +} diff --git a/source/widgets/sources/templates/entry.html.tpl b/source/widgets/sources/templates/entry.html.tpl new file mode 100644 index 0000000..92b794c --- /dev/null +++ b/source/widgets/sources/templates/entry.html.tpl @@ -0,0 +1 @@ +
  • {{name}}
  • diff --git a/source/widgets/sources/templates/main.html.tpl b/source/widgets/sources/templates/main.html.tpl new file mode 100644 index 0000000..3f9a9a7 --- /dev/null +++ b/source/widgets/sources/templates/main.html.tpl @@ -0,0 +1,3 @@ +
      + {{entries}} +
    diff --git a/source/widgets/weekview/logic.ts b/source/widgets/weekview/logic.ts new file mode 100644 index 0000000..305fd49 --- /dev/null +++ b/source/widgets/weekview/logic.ts @@ -0,0 +1,875 @@ +namespace _zeitbild.frontend_web.widgets.weekview +{ + + /** + */ + export class class_widget_weekview extends _zeitbild.class_widget + { + + /** + */ + private container : (null | Element); + + + /** + */ + private action_select_day : ( + ( + date : lib_plankton.pit.type_date + ) + => + void + ); + + + /** + */ + private action_select_event : ( + ( + calendar_id : _zeitbild.frontend_web.type.calendar_id, + access_level : _zeitbild.frontend_web.type.enum_access_level, + event_id : _zeitbild.frontend_web.type.local_resource_event_id + ) + => + void + ); + + + /** + */ + public constructor( + options : { + action_select_day ?: ( + ( + date : lib_plankton.pit.type_date + ) + => + void + ); + action_select_event ?: ( + ( + calendar_id : _zeitbild.frontend_web.type.calendar_id, + access_level : _zeitbild.frontend_web.type.enum_access_level, + event_id : _zeitbild.frontend_web.type.local_resource_event_id + ) + => + void + ); + } = {} + ) + { + options = Object.assign( + { + "action_select_day": (date) => {}, + "action_select_event": (calendar_id, access_level, event_id) => {}, + }, + options + ); + super(); + this.container = null; + this.action_select_day = options.action_select_day; + this.action_select_event = options.action_select_event; + } + + + /** + */ + private static event_generate_tooltip( + calendar_name : string, + event_object : _zeitbild.frontend_web.type.event_object + ) : string + { + return ( + lib_plankton.string.coin( + "[{{calendar_name}}] {{event_name}}\n", + { + "calendar_name": calendar_name, + "event_name": event_object.name, + } + ) + + + "--\n" + + + ( + (event_object.begin.time !== null) + ? + lib_plankton.string.coin( + "{{label}}: {{value}}\n", + { + "label": lib_plankton.translate.get("event.begin"), + "value": lib_plankton.string.coin( + "{{hour}}:{{minute}}", + { + "hour": event_object.begin.time.hour.toFixed(0).padStart(2, "0"), + "minute": event_object.begin.time.minute.toFixed(0).padStart(2, "0"), + } + ), // TODO: outsource + } + ) + : + "" + ) + + + ( + (event_object.end !== null) + ? + lib_plankton.string.coin( + "{{label}}: {{value}}\n", + { + "label": lib_plankton.translate.get("event.end"), + "value": ( + [ + ( + ( + (event_object.end.date.year !== event_object.begin.date.year) + || + (event_object.end.date.month !== event_object.begin.date.month) + || + (event_object.end.date.day !== event_object.begin.date.day) + ) + ? + lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": event_object.end.date.year.toFixed(0).padStart(4, "0"), + "month": event_object.end.date.month.toFixed(0).padStart(2, "0"), + "day": event_object.end.date.day.toFixed(0).padStart(2, "0"), + } + ) + : + null + ), + ( + (event_object.end.time !== null) + ? + lib_plankton.string.coin( + "{{hour}}:{{minute}}", + { + "hour": event_object.end.time.hour.toFixed(0).padStart(2, "0"), + "minute": event_object.end.time.minute.toFixed(0).padStart(2, "0"), + } + ) + : + null + ), + ] + .filter(x => (x !== null)) + .join(",") + ), + } + ) + : + "" + ) + + + ( + (event_object.location !== null) + ? + ( + lib_plankton.string.coin( + "{{label}}: {{value}}\n", + { + "label": lib_plankton.translate.get("event.location"), + "value": event_object.location, + } + ) + ) + : + "" + ) + /* + + + ( + (event_object.description !== null) + ? + ( + "--\n" + + + lib_plankton.string.coin( + "{{description}}\n", + { + "description": event_object.description, + } + ) + ) + : + "" + ) + */ + ); + } + + + /** + * @todo kein "while" + */ + private static async calendar_view_table_data( + calendar_ids : ( + null + | + Array<_zeitbild.frontend_web.type.calendar_id> + ), + from : { + year : int; + week : int; + }, + to : { + year : int; + week : int; + }, + timezone_shift : int + ) : Promise< + { + sources : lib_plankton.map.type_map< + _zeitbild.frontend_web.type.calendar_id, + { + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + } + >; + rows : Array< + { + week : int; + data : Array< + { + pit : lib_plankton.pit.type_pit; + entries : Array< + { + calendar_id : _zeitbild.frontend_web.type.calendar_id; + event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); + event_object : _zeitbild.frontend_web.type.event_object; + } + >; + today : boolean; + } + >; + } + > + } + > + { + const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); + const from_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( + { + "year": (from as {year : int; week : int}).year, + "week": (from as {year : int; week : int}).week, + "day": 1, + }, + { + "timezone_shift": (timezone_shift as int), + } + ); + const to_pit : lib_plankton.pit.type_pit = lib_plankton.pit.from_ywd( + { + "year": (to as {year : int; week : int}).year, + "week": (to as {year : int; week : int}).week, + "day": 1, + }, + { + "timezone_shift": (timezone_shift as int), + } + ); + + // prepare + const entries : Array< + { + calendar_id : _zeitbild.frontend_web.type.calendar_id; + calendar_name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); + event_object : _zeitbild.frontend_web.type.event_object; + } + > = await _zeitbild.frontend_web.backend.events( + from_pit, + to_pit, + { + "calendar_ids": calendar_ids, + } + ); + let result : { + sources : lib_plankton.map.type_map< + _zeitbild.frontend_web.type.calendar_id, + { + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + } + >; + rows : Array< + { + week : int; + data : Array< + { + pit : lib_plankton.pit.type_pit; + entries : Array< + { + calendar_id : _zeitbild.frontend_web.type.calendar_id; + event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); + event_object : _zeitbild.frontend_web.type.event_object; + } + >; + today : boolean; + } + >; + } + >; + } = { + "sources": lib_plankton.map.hashmap.implementation_map( + lib_plankton.map.hashmap.make( + x => x.toFixed(0), + { + "pairs": ( + entries + .map( + (entry) => ( + { + "key": entry.calendar_id, + "value": { + "name": entry.calendar_name, + "access_level": entry.access_level, + } + } + ) + ) + ) + } + ) + ), + "rows": [], + }; + let row : Array< + { + pit : lib_plankton.pit.type_pit; + entries : Array< + { + calendar_id : _zeitbild.frontend_web.type.calendar_id; + event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); + event_object : _zeitbild.frontend_web.type.event_object; + } + >; + today : boolean; + } + > = []; + let day : int = 0; + while (true) { + const pit_current : lib_plankton.pit.type_pit = lib_plankton.pit.shift_day( + from_pit, + day + ); + if ( + lib_plankton.pit.is_before( + pit_current, + to_pit + ) + ) { + day += 1; + row.push( + { + "pit": pit_current, + "entries": [], + "today": false, // TODO + } + ); + if (day % 7 === 0) { + result.rows.push( + { + "week": ( + (from as {year : int; week : int}).week + + + Math.floor(day / 7) + - + 1 // TODO + ), + "data": row + } + ); + row = []; + } + else { + // do nothing + } + } + else { + break; + } + } + + // fill + { + // events + ( + entries + .forEach( + (entry) => { + const distance_seconds : int = ( + lib_plankton.pit.from_datetime(entry.event_object.begin) + - + from_pit + ); + const distance_days : int = (distance_seconds / (60 * 60 * 24)); + + const week : int = Math.floor(Math.floor(distance_days) / 7); + const day : int = (Math.floor(distance_days) % 7); + + if ((week >= 0) && (week < result.rows.length)) { + result.rows[week].data[day].entries.push(entry); + } + else { + // do nothing + } + } + ) + ); + // today + { + const distance_seconds : int = ( + now_pit + - + from_pit + ); + const distance_days : int = (distance_seconds / (60 * 60 * 24)); + + const week : int = Math.floor(Math.floor(distance_days) / 7); + const day : int = (Math.floor(distance_days) % 7); + + if ((week >= 0) && (week < result.rows.length)) { + result.rows[week].data[day].today = true; + } + else { + // do nothing + } + } + } + + return Promise.resolve(result); + } + + + /** + */ + private async table_rows( + options : { + calendar_ids ?: ( + null + | + Array<_zeitbild.frontend_web.type.calendar_id> + ); + from ?: { + year : int; + week : int; + }; + to ?: { + year : int; + week : int; + }; + timezone_shift ?: int; + action_select ?: ( + ( + calendar_id : _zeitbild.frontend_web.type.calendar_id, + event_id : _zeitbild.frontend_web.type.local_resource_event_id + ) + => + void + ) + } = {} + ) : Promise + { + const now_pit : lib_plankton.pit.type_pit = lib_plankton.pit.now(); + options = Object.assign( + { + "calendar_ids": null, + "from": lib_plankton.call.convey( + now_pit, + [ + (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, -1), + lib_plankton.pit.to_ywd, + x => ({"year": x.year, "week": x.week}), + ] + ), + "to": lib_plankton.call.convey( + now_pit, + [ + (x : lib_plankton.pit.type_pit) => lib_plankton.pit.shift_week(x, +4), + lib_plankton.pit.to_ywd, + x => ({"year": x.year, "week": x.week}), + ] + ), + "timezone_shift": 0, + }, + options + ); + const stuff : { + sources : lib_plankton.map.type_map< + _zeitbild.frontend_web.type.calendar_id, + { + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + } + >; + rows : Array< + { + week : int; + data : Array< + { + pit : lib_plankton.pit.type_pit; + entries : Array< + { + calendar_id : _zeitbild.frontend_web.type.calendar_id; + event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id); + event_object : _zeitbild.frontend_web.type.event_object; + } + >; + today : boolean; + } + >; + } + >; + } = await class_widget_weekview.calendar_view_table_data( + options.calendar_ids, + options.from, + options.to, + options.timezone_shift + ); + const sources : lib_plankton.map.type_map< + _zeitbild.frontend_web.type.calendar_id, + { + name : string; + access_level : _zeitbild.frontend_web.type.enum_access_level; + color : lib_plankton.color.type_color; + } + > = lib_plankton.map.hashmap.implementation_map( + lib_plankton.map.hashmap.make( + (x => x.toFixed(0)), + { + "pairs": ( + lib_plankton.map.dump( + stuff.sources + ) + .map( + (pair) => ({ + "key": pair.key, + "value": { + "name": pair.value.name, + "access_level": pair.value.access_level, + "color": lib_plankton.color.give_generic( + (pair.key - 1), + { + "saturation": 0.375, + "value": 0.375, + } + ), + } + }) + ) + ) + } + ) + ); + return ( + await _zeitbild.frontend_web.helpers.promise_row( + stuff.rows + .map( + (row) => async () => _zeitbild.frontend_web.helpers.template_coin( + "widget-weekview", + "tableview-row", + { + "week": row.week.toFixed(0).padStart(2, "0"), + "cells": ( + await _zeitbild.frontend_web.helpers.promise_row( + row.data + .map( + (cell) => async () => _zeitbild.frontend_web.helpers.template_coin( + "widget-weekview", + "tableview-cell", + { + "extra_classes": ( + [""] + .concat(cell.today ? ["calendar-cell-today"] : []) + .join(" ") + ), + "title": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] + ), + "day": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ), + ] + ), + "rel": lib_plankton.call.convey( + cell.pit, + [ + lib_plankton.pit.to_datetime, + (x : lib_plankton.pit.type_datetime) => lib_plankton.string.coin( + "{{year}}-{{month}}-{{day}}", + { + "year": x.date.year.toFixed(0).padStart(4, "0"), + "month": x.date.month.toFixed(0).padStart(2, "0"), + "day": x.date.day.toFixed(0).padStart(2, "0"), + } + ) + ] + ), + "entries": ( + await _zeitbild.frontend_web.helpers.promise_row( + cell.entries + .map( + (entry) => () => _zeitbild.frontend_web.helpers.template_coin( + "widget-weekview", + "tableview-cell-entry", + { + "color": lib_plankton.color.output_hex( + sources.get( + entry.calendar_id + ).color + ), + "title": class_widget_weekview.event_generate_tooltip( + sources.get( + entry.calendar_id + ).name, + entry.event_object + ), + "name": entry.event_object.name, + "rel": lib_plankton.string.coin( + "{{calendar_id}}/{{event_id}}/{{access_level}}", + { + "calendar_id": entry.calendar_id.toFixed(0), + "event_id": ( + (entry.event_id === null) + ? + "-" + : + entry.event_id.toFixed(0) + ), + "access_level": (() => { + const access_level : _zeitbild.frontend_web.type.enum_access_level = sources.get(entry.calendar_id).access_level; + switch (access_level) { + case _zeitbild.frontend_web.type.enum_access_level.none: return "none"; + case _zeitbild.frontend_web.type.enum_access_level.view: return "view"; + case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit"; + case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin"; + } + }) (), + } + ), + "additional_classes": lib_plankton.string.coin( + " access_level-{{access_level}}", + { + "access_level": (() => { + const access_level : _zeitbild.frontend_web.type.enum_access_level = sources.get(entry.calendar_id).access_level; + switch (access_level) { + case _zeitbild.frontend_web.type.enum_access_level.none: return "none"; + case _zeitbild.frontend_web.type.enum_access_level.view: return "view"; + case _zeitbild.frontend_web.type.enum_access_level.edit: return "edit"; + case _zeitbild.frontend_web.type.enum_access_level.admin: return "admin"; + } + }) (), + } + ), + } + ) + ) + ) + ).join(""), + } + ) + ) + ) + ).join(""), + } + ) + ) + ) + ).join(""); + } + + + /** + */ + private async update( + year : int, + week : int, + count : int, + options : { + update_controls ?: boolean; + } = {} + ) : Promise + { + options = Object.assign( + { + "update_controls": true, + }, + options + ); + const context : Element = this.container; + // controls + { + if (! options.update_controls) { + // do nothing + } + else { + (context.querySelector(".weekview-control-year > input") as HTMLInputElement).value = year.toFixed(0); + (context.querySelector(".weekview-control-week > input") as HTMLInputElement).value = week.toFixed(0); + (context.querySelector(".weekview-control-count > input") as HTMLInputElement).value = count.toFixed(0); + } + } + // table + { + context.querySelector(".weekview-table tbody").innerHTML = await this.table_rows( + { + "calendar_ids": null, + // TODO + "from": { + "year": year, + "week": week + }, + // TODO + "to": { + "year": year, + "week": (week + count) + }, + "timezone_shift": /*conf.timezone_shift*/0, + } + ); + // cells + { + context.querySelectorAll(".calendar-cell-regular").forEach( + (element) => { + element.addEventListener( + "click", + (event) => { + if (! (element === event.target)) { + // do nothing + } + else { + const rel : string = element.getAttribute("rel"); + const parts : Array = rel.split("-"); + const date : lib_plankton.pit.type_date = { + "year": parseInt(parts[0]), + "month": parseInt(parts[1]), + "day": parseInt(parts[2]), + }; + this.action_select_day(date); + } + } + ); + } + ); + } + // events + { + context.querySelectorAll(".calendar-event_entry").forEach( + (element) => { + element.addEventListener( + "click", + () => { + const rel : string = element.getAttribute("rel"); + const parts : Array = rel.split("/"); + const calendar_id : _zeitbild.frontend_web.type.calendar_id = parseInt(parts[0]); + const event_id : (null | _zeitbild.frontend_web.type.local_resource_event_id) = ( + (parts[1] === "-") + ? + null + : + parseInt(parts[1]) + ); + const access_level : _zeitbild.frontend_web.type.enum_access_level = (() => { + switch (parts[2]) { + case "none": return _zeitbild.frontend_web.type.enum_access_level.none; + case "view": return _zeitbild.frontend_web.type.enum_access_level.view; + case "edit": return _zeitbild.frontend_web.type.enum_access_level.edit; + case "admin": return _zeitbild.frontend_web.type.enum_access_level.admin; + } + }) (); + this.action_select_event( + calendar_id, + access_level, + event_id + ); + } + ); + } + ); + } + } + return Promise.resolve(undefined); + } + + + /** + * [implementation] + */ + public async load( + target_element : Element + ) : Promise + { + target_element.innerHTML = await _zeitbild.frontend_web.helpers.template_coin( + "widget-weekview", + "main", + { + "label_control_year": lib_plankton.translate.get("widget.weekview.controls.year"), + "label_control_week": lib_plankton.translate.get("widget.weekview.controls.week"), + "label_control_count": lib_plankton.translate.get("widget.weekview.controls.count"), + "label_control_apply": lib_plankton.translate.get("widget.weekview.controls.apply"), + } + ); + this.container = target_element.querySelector(".weekview"); + // controls + { + target_element.querySelector(".weekview-control-apply").addEventListener( + "select", + (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, + } + ); + } + ); + } + // table + { + const ywd_now : lib_plankton.pit.type_ywd = lib_plankton.pit.to_ywd(lib_plankton.pit.now()); + let year : int = ywd_now.year; + let week : int = Math.max(0, (ywd_now.week - 1)); + let count : int = 5; + await this.update( + year, + week, + count, + { + "update_controls": true, + } + ); + } + return Promise.resolve(undefined); + } + + } + +} diff --git a/source/pages/events/templates/tableview.html.tpl b/source/widgets/weekview/templates/main.html.tpl similarity index 51% rename from source/pages/events/templates/tableview.html.tpl rename to source/widgets/weekview/templates/main.html.tpl index 4028def..6357ffc 100644 --- a/source/pages/events/templates/tableview.html.tpl +++ b/source/widgets/weekview/templates/main.html.tpl @@ -1,10 +1,20 @@ -
    -
    -
      -{{sources}} -
    +
    +
    + + + +
    -
    +
    @@ -19,7 +29,6 @@ -{{rows}}
    diff --git a/source/pages/events/templates/tableview-cell-entry.html.tpl b/source/widgets/weekview/templates/tableview-cell-entry.html.tpl similarity index 100% rename from source/pages/events/templates/tableview-cell-entry.html.tpl rename to source/widgets/weekview/templates/tableview-cell-entry.html.tpl diff --git a/source/pages/events/templates/tableview-cell.html.tpl b/source/widgets/weekview/templates/tableview-cell.html.tpl similarity index 100% rename from source/pages/events/templates/tableview-cell.html.tpl rename to source/widgets/weekview/templates/tableview-cell.html.tpl diff --git a/source/pages/events/templates/tableview-row.html.tpl b/source/widgets/weekview/templates/tableview-row.html.tpl similarity index 100% rename from source/pages/events/templates/tableview-row.html.tpl rename to source/widgets/weekview/templates/tableview-row.html.tpl diff --git a/tools/makefile b/tools/makefile index 67bda0b..0b0ee5f 100644 --- a/tools/makefile +++ b/tools/makefile @@ -32,6 +32,8 @@ ${dir_build}/index.html: \ .PHONY: templates templates: \ + templates-widgets-sources \ + templates-widgets-weekview \ templates-pages-calendar_add \ templates-pages-calendar_edit \ templates-pages-event_add \ @@ -39,6 +41,20 @@ templates: \ templates-pages-events \ templates-pages-login +.PHONY: templates-widgets-sources +templates-widgets-sources: \ + $(wildcard ${dir_source}/widgets/sources/templates/*) + @ ${cmd_log} "templates:widgets:sources …" + @ ${cmd_mkdir} ${dir_build}/templates/widget-sources + @ ${cmd_cp} -r -u -v ${dir_source}/widgets/sources/templates/* ${dir_build}/templates/widget-sources/ + +.PHONY: templates-widgets-weekview +templates-widgets-weekview: \ + $(wildcard ${dir_source}/widgets/weekview/templates/*) + @ ${cmd_log} "templates:widgets:weekview …" + @ ${cmd_mkdir} ${dir_build}/templates/widget-weekview + @ ${cmd_cp} -r -u -v ${dir_source}/widgets/weekview/templates/* ${dir_build}/templates/widget-weekview/ + .PHONY: templates-pages-calendar_add templates-pages-calendar_add: \ $(wildcard ${dir_source}/pages/calendar_add/templates/*) @@ -94,10 +110,12 @@ logic: ${dir_build}/logic.js ${dir_temp}/logic-unlinked.js: \ ${dir_lib}/plankton/plankton.d.ts \ ${dir_source}/logic/helpers.ts \ + ${dir_source}/logic/widget.ts \ ${dir_source}/logic/conf.ts \ ${dir_source}/logic/types.ts \ ${dir_source}/logic/backend.ts \ - ${dir_source}/logic/view.ts \ + ${dir_source}/widgets/sources/logic.ts \ + ${dir_source}/widgets/weekview/logic.ts \ ${dir_source}/pages/login/logic.ts \ ${dir_source}/pages/logout/logic.ts \ ${dir_source}/pages/oidc_finish/logic.ts \