namespace _zeitbild.frontend_web.widgets.weekview { /** */ type type_entry = { 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; }; /** */ type type_get_entries = ( ( from_pit : lib_plankton.pit.type_pit, to_pit : lib_plankton.pit.type_pit, calendar_ids : Array<_zeitbild.frontend_web.type.calendar_id> ) => Promise> ); /** */ export class class_widget_weekview extends _zeitbild.class_widget { /** */ private get_entries : type_get_entries; /** */ private container : (null | Element); /** */ 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 ); /** */ private action_select_day : ( ( date : lib_plankton.pit.type_date ) => void ); /** */ public constructor( get_entries : type_get_entries, options : { 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 ); action_select_day ?: ( ( date : lib_plankton.pit.type_date ) => void ); } = {} ) { options = Object.assign( { "action_select_day": (date) => {}, "action_select_event": (calendar_id, access_level, event_id) => {}, }, options ); super(); this.get_entries = get_entries; 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.link !== null) ? ( lib_plankton.string.coin( "{{label}}: {{value}}\n", { "label": lib_plankton.translate.get("event.link"), "value": event_object.link, } ) ) : "" ) /* + ( (event_object.description !== null) ? ( "--\n" + lib_plankton.string.coin( "{{description}}\n", { "description": event_object.description, } ) ) : "" ) */ ); } /** * @todo kein "while" */ private 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 = await this.get_entries( from_pit, to_pit, 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 this.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 { if (! await _zeitbild.frontend_web.backend.is_logged_in()) { // do nothing } else { 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 { if (! await _zeitbild.frontend_web.backend.is_logged_in()) { // do nothing } else { 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"), "label_weekday_monday": lib_plankton.translate.get("common.weekday.monday"), "label_weekday_tuesday": lib_plankton.translate.get("common.weekday.tuesday"), "label_weekday_wednesday": lib_plankton.translate.get("common.weekday.wednesday"), "label_weekday_thursday": lib_plankton.translate.get("common.weekday.thursday"), "label_weekday_friday": lib_plankton.translate.get("common.weekday.friday"), "label_weekday_saturday": lib_plankton.translate.get("common.weekday.saturday"), "label_weekday_sunday": lib_plankton.translate.get("common.weekday.sunday"), } ); this.container = target_element.querySelector(".weekview"); // controls { target_element.querySelector(".weekview-control-apply").addEventListener( "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, } ); } ); } // 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); } } }