mapcomplete/UI/Input/OpeningHours/OpeningHoursPickerTable.ts

294 lines
10 KiB
TypeScript
Raw Normal View History

2020-10-04 01:04:46 +02:00
import {InputElement} from "../InputElement";
import {OpeningHour} from "../../../Logic/OpeningHours";
import {UIEventSource} from "../../../Logic/UIEventSource";
import {Utils} from "../../../Utils";
import {UIElement} from "../../UIElement";
2020-10-06 02:09:09 +02:00
import Translations from "../../i18n/Translations";
2020-10-23 01:20:48 +02:00
import {Browser} from "leaflet";
2020-10-04 01:04:46 +02:00
/**
* This is the base-table which is selectable by hovering over it.
* It will genarate the currently selected opening hour.
*/
2020-10-06 01:37:02 +02:00
export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]> {
2020-10-04 01:04:46 +02:00
public readonly IsSelected: UIEventSource<boolean>;
private readonly weekdays: UIEventSource<UIElement[]>;
2020-10-06 02:09:09 +02:00
public static readonly days: UIElement[] =
[
Translations.t.general.weekdays.abbreviations.monday,
Translations.t.general.weekdays.abbreviations.tuesday,
Translations.t.general.weekdays.abbreviations.wednesday,
Translations.t.general.weekdays.abbreviations.thursday,
Translations.t.general.weekdays.abbreviations.friday,
Translations.t.general.weekdays.abbreviations.saturday,
Translations.t.general.weekdays.abbreviations.sunday
]
2020-10-04 01:04:46 +02:00
2020-10-06 01:37:02 +02:00
private readonly source: UIEventSource<OpeningHour[]>;
2020-10-04 01:04:46 +02:00
2020-10-06 01:37:02 +02:00
constructor(weekdays: UIEventSource<UIElement[]>, source?: UIEventSource<OpeningHour[]>) {
2020-10-04 01:04:46 +02:00
super(weekdays);
this.weekdays = weekdays;
2020-10-06 01:37:02 +02:00
this.source = source ?? new UIEventSource<OpeningHour[]>([]);
2020-10-04 01:04:46 +02:00
this.IsSelected = new UIEventSource<boolean>(false);
this.SetStyle("width:100%;height:100%;display:block;");
}
InnerRender(): string {
let rows = "";
const self = this;
for (let h = 0; h < 24; h++) {
let hs = "" + h;
if (hs.length == 1) {
hs = "0" + hs;
}
rows += `<tr><td rowspan="2" class="oh-left-col oh-timecell-full">${hs}:00</td>` +
2020-10-23 01:20:48 +02:00
Utils.Times(weekday => `<td id="${this.id}-timecell-${weekday}-${h}" class="oh-timecell oh-timecell-full oh-timecell-${weekday}"></td>`, 7) +
'</tr><tr>' +
Utils.Times(id => `<td id="${this.id}-timecell-${id}-${h}-30" class="oh-timecell oh-timecell-half oh-timecell-${id}"></td>`, 7) +
2020-10-04 01:04:46 +02:00
'</tr>';
}
2020-10-08 19:03:00 +02:00
let days = OpeningHoursPickerTable.days.map((day, i) => {
const innerContent = self.weekdays.data[i]?.Render() ?? "";
return day.Render() + "<span style='width:100%; display:block; position: relative;'>"+innerContent+"</span>";
}).join("</th><th width='14%'>");
2020-10-04 12:55:44 +02:00
return `<table id="oh-table-${this.id}" class="oh-table"><tr><th></th><th width='14%'>${days}</th></tr>${rows}</table>`;
2020-10-04 01:04:46 +02:00
}
protected InnerUpdate() {
const self = this;
const table = (document.getElementById(`oh-table-${this.id}`) as HTMLTableElement);
2020-10-23 01:20:48 +02:00
console.log("Inner update!")
2020-10-04 01:04:46 +02:00
if (table === undefined || table === null) {
return;
}
for (const uielement of this.weekdays.data) {
uielement.Update();
}
let mouseIsDown = false;
let selectionStart: [number, number] = undefined;
let selectionEnd: [number, number] = undefined;
function h(timeSegment: number) {
return Math.floor(timeSegment / 2);
}
function m(timeSegment: number) {
return (timeSegment % 2) * 30;
}
function startSelection(i: number, j: number) {
mouseIsDown = true;
selectionStart = [i, j];
selectionEnd = [i, j];
}
function endSelection() {
if (selectionStart === undefined) {
return;
}
if (!mouseIsDown) {
return;
}
mouseIsDown = false
const dStart = Math.min(selectionStart[1], selectionEnd[1]);
const dEnd = Math.max(selectionStart[1], selectionEnd[1]);
const timeStart = Math.min(selectionStart[0], selectionEnd[0]) - 1;
const timeEnd = Math.max(selectionStart[0], selectionEnd[0]) - 1;
for (let weekday = dStart; weekday <= dEnd; weekday++) {
const oh: OpeningHour = {
weekday: weekday,
startHour: h(timeStart),
startMinutes: m(timeStart),
endHour: h(timeEnd + 1),
endMinutes: m(timeEnd + 1)
}
2020-10-23 01:20:48 +02:00
if (oh.endHour > 23) {
2020-10-04 01:04:46 +02:00
oh.endHour = 24;
oh.endMinutes = 0;
}
2020-10-06 01:37:02 +02:00
self.source.data.push(oh);
2020-10-04 01:04:46 +02:00
}
2020-10-06 01:37:02 +02:00
self.source.ping();
2020-10-04 01:04:46 +02:00
// Clear the highlighting
2020-10-23 01:20:48 +02:00
let header = table.rows[0];
for (let j = 1; j < header.cells.length; j++) {
header.cells[j].classList?.remove("oh-timecol-selected")
}
2020-10-04 01:04:46 +02:00
for (let i = 1; i < table.rows.length; i++) {
let row = table.rows[i]
for (let j = 0; j < row.cells.length; j++) {
let cell = row.cells[j]
2020-10-21 20:54:15 +02:00
cell?.classList?.remove("oh-timecell-selected");
row.classList?.remove("oh-timerow-selected");
2020-10-04 01:04:46 +02:00
}
}
}
table.onmouseup = () => {
endSelection();
};
table.onmouseleave = () => {
endSelection();
};
2020-10-23 01:20:48 +02:00
let lastSelectionIend, lastSelectionJEnd;
2020-10-04 01:04:46 +02:00
function selectAllBetween(iEnd, jEnd) {
2020-10-23 01:20:48 +02:00
if (lastSelectionIend === iEnd && lastSelectionJEnd === jEnd) {
return; // We already did this
}
lastSelectionIend = iEnd;
lastSelectionJEnd = jEnd;
2020-10-04 01:04:46 +02:00
let iStart = selectionStart[0];
let jStart = selectionStart[1];
if (iStart > iEnd) {
const h = iStart;
iStart = iEnd;
iEnd = h;
}
if (jStart > jEnd) {
const h = jStart;
jStart = jEnd;
jEnd = h;
}
2020-10-23 01:20:48 +02:00
let header = table.rows[0];
for (let j = 1; j < header.cells.length; j++) {
let cell = header.cells[j]
cell.classList?.remove("oh-timecol-selected-round-left");
cell.classList?.remove("oh-timecol-selected-round-right");
if (jStart + 1 <= j && j <= jEnd + 1) {
cell.classList?.add("oh-timecol-selected")
if (jStart + 1 == j) {
cell.classList?.add("oh-timecol-selected-round-left");
}
if (jEnd + 1 == j) {
cell.classList?.add("oh-timecol-selected-round-right");
}
} else {
cell.classList?.remove("oh-timecol-selected")
}
}
2020-10-04 01:04:46 +02:00
for (let i = 1; i < table.rows.length; i++) {
2020-10-23 01:20:48 +02:00
let row = table.rows[i];
if (iStart <= i && i <= iEnd) {
row.classList?.add("oh-timerow-selected")
} else {
row.classList?.remove("oh-timerow-selected")
}
2020-10-04 01:04:46 +02:00
for (let j = 0; j < row.cells.length; j++) {
let cell = row.cells[j]
if (cell === undefined) {
continue;
}
let offset = 0;
if (i % 2 == 1) {
if (j == 0) {
2020-10-23 01:20:48 +02:00
// This is the first column of a full hour -> This is the time indication (skip)
2020-10-04 01:04:46 +02:00
continue;
}
offset = -1;
}
2020-10-23 01:20:48 +02:00
2020-10-04 01:04:46 +02:00
if (iStart <= i && i <= iEnd &&
jStart <= j + offset && j + offset <= jEnd) {
cell?.classList?.add("oh-timecell-selected")
} else {
2020-10-21 20:54:15 +02:00
cell?.classList?.remove("oh-timecell-selected")
2020-10-04 01:04:46 +02:00
}
2020-10-21 20:54:15 +02:00
2020-10-04 01:04:46 +02:00
}
}
}
for (let i = 1; i < table.rows.length; i++) {
let row = table.rows[i]
for (let j = 0; j < row.cells.length; j++) {
2020-10-08 19:03:00 +02:00
let cell = row.cells[j]
2020-10-04 01:04:46 +02:00
let offset = 0;
if (i % 2 == 1) {
if (j == 0) {
continue;
}
offset = -1;
}
cell.onmousedown = (ev) => {
ev.preventDefault();
startSelection(i, j + offset)
selectAllBetween(i, j + offset);
}
cell.ontouchstart = (ev) => {
ev.preventDefault();
startSelection(i, j + offset);
selectAllBetween(i, j + offset);
}
cell.onmouseenter = () => {
if (mouseIsDown) {
selectionEnd = [i, j + offset];
selectAllBetween(i, j + offset)
}
}
cell.ontouchmove = (ev: TouchEvent) => {
ev.preventDefault();
for (const k in ev.targetTouches) {
const touch = ev.targetTouches[k];
2020-10-05 20:42:54 +02:00
if(touch.clientX === undefined || touch.clientY === undefined){
continue;
}
2020-10-04 01:04:46 +02:00
const elUnderTouch = document.elementFromPoint(
2020-10-05 20:42:54 +02:00
touch.clientX,
touch.clientY
2020-10-04 01:04:46 +02:00
);
// @ts-ignore
const f = elUnderTouch.onmouseenter;
if (f) {
f();
}
}
}
cell.ontouchend = (ev) => {
ev.preventDefault();
2020-10-05 20:42:54 +02:00
endSelection();
2020-10-04 01:04:46 +02:00
}
}
}
}
2020-10-06 01:37:02 +02:00
IsValid(t: OpeningHour[]): boolean {
2020-10-04 01:04:46 +02:00
return true;
}
2020-10-06 01:37:02 +02:00
GetValue(): UIEventSource<OpeningHour[]> {
2020-10-04 01:04:46 +02:00
return this.source;
}
}