Fix opening hours input element

This commit is contained in:
pietervdvn 2021-06-16 14:23:53 +02:00
parent 94f9a0de56
commit 64ec06bfc8
19 changed files with 643 additions and 599 deletions

View file

@ -102,9 +102,13 @@ export default class SimpleMetaTagger {
SimpleMetaTagger.GetCountryCodeFor(lon, lat, (countries) => {
try {
const oldCountry = feature.properties["_country"];
feature.properties["_country"] = countries[0].trim().toLowerCase();
const tagsSource = State.state.allElements.getEventSourceById(feature.properties.id);
tagsSource.ping();
if (oldCountry !== feature.properties["_country"]) {
const tagsSource = State.state.allElements.getEventSourceById(feature.properties.id);
tagsSource.ping();
}
} catch (e) {
console.warn(e)
}

View file

@ -19,6 +19,9 @@ export default class Combine extends BaseUIElement {
protected InnerConstructElement(): HTMLElement {
const el = document.createElement("span")
try{
for (const subEl of this.uiElements) {
if(subEl === undefined || subEl === null){
continue;
@ -28,6 +31,11 @@ export default class Combine extends BaseUIElement {
el.appendChild(subHtml)
}
}
}catch(e){
const domExc = e as DOMException
console.error("DOMException: ", domExc.name)
el.appendChild(new FixedUiElement("Could not generate this combine!").SetClass("alert").ConstructElement())
}
return el;
}

View file

@ -6,10 +6,14 @@ export default class Table extends BaseUIElement {
private readonly _header: BaseUIElement[];
private readonly _contents: BaseUIElement[][];
private readonly _contentStyle: string[][];
constructor(header: (BaseUIElement | string)[], contents: (BaseUIElement | string)[][]) {
constructor(header: (BaseUIElement | string)[],
contents: (BaseUIElement | string)[][],
contentStyle?: string[][]) {
super();
this._header = header.map(Translations.W);
this._contentStyle = contentStyle ?? [];
this._header = header?.map(Translations.W);
this._contents = contents.map(row => row.map(Translations.W));
}
@ -28,15 +32,23 @@ export default class Table extends BaseUIElement {
table.appendChild(tr)
}
for (const row of this._contents) {
for (let i = 0; i < this._contents.length; i++){
let row = this._contents[i];
const tr = document.createElement("tr")
for (const elem of row) {
const htmlElem = elem.ConstructElement()
for (let j = 0; j < row.length; j++){
let elem = row[j];
const htmlElem = elem?.ConstructElement()
if (htmlElem === undefined) {
continue;
}
let style = undefined;
if(this._contentStyle !== undefined && this._contentStyle[i] !== undefined && this._contentStyle[j]!== undefined){
style = this._contentStyle[i][j]
}
const td = document.createElement("td")
td.style.cssText = style;
td.appendChild(htmlElem)
tr.appendChild(td)
}

View file

@ -18,7 +18,7 @@ export class VariableUiElement extends BaseUIElement {
}
if (contents === undefined) {
return
return el;
}
if (typeof contents === "string") {
el.innerHTML = contents

View file

@ -102,6 +102,8 @@ export default abstract class BaseUIElement {
if(this.InnerConstructElement === undefined){
throw "ERROR! This is not a correct baseUIElement: "+this.constructor.name
}
try{
const el = this.InnerConstructElement();
@ -149,7 +151,13 @@ export default abstract class BaseUIElement {
el.addEventListener('mouseout', () => self._onHover.setData(false));
}
return el
return el}catch(e){
const domExc = e as DOMException;
if(domExc){
console.log("An exception occured", domExc.code, domExc.message, domExc.name )
}
console.error(e)
}
}
public AsMarkdown(): string{

View file

@ -1,324 +0,0 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine";
import State from "../../State";
import {FixedUiElement} from "../Base/FixedUiElement";
import {OH} from "./OpeningHours";
import Translations from "../i18n/Translations";
import Constants from "../../Models/Constants";
import opening_hours from "opening_hours";
import BaseUIElement from "../BaseUIElement";
export default class OpeningHoursVisualization extends UIElement {
private static readonly weekdays = [
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,
]
private readonly _key: string;
constructor(tags: UIEventSource<any>, key: string) {
super(tags);
this._key = key;
this.ListenTo(UIEventSource.Chronic(60 * 1000)); // Automatically reload every minute
this.ListenTo(UIEventSource.Chronic(500, () => {
return tags.data._country === undefined;
}));
}
private static GetRanges(oh: any, from: Date, to: Date): ({
isOpen: boolean,
isSpecial: boolean,
comment: string,
startDate: Date,
endDate: Date
}[])[] {
const values = [[], [], [], [], [], [], []];
const start = new Date(from);
// We go one day more into the past, in order to force rendering of holidays in the start of the period
start.setDate(from.getDate() - 1);
const iterator = oh.getIterator(start);
let prevValue = undefined;
while (iterator.advance(to)) {
if (prevValue) {
prevValue.endDate = iterator.getDate() as Date
}
const endDate = new Date(iterator.getDate()) as Date;
endDate.setHours(0, 0, 0, 0)
endDate.setDate(endDate.getDate() + 1);
const value = {
isSpecial: iterator.getUnknown(),
isOpen: iterator.getState(),
comment: iterator.getComment(),
startDate: iterator.getDate() as Date,
endDate: endDate // Should be overwritten by the next iteration
}
prevValue = value;
if (value.comment === undefined && !value.isOpen && !value.isSpecial) {
// simply closed, nothing special here
continue;
}
if (value.startDate < from) {
continue;
}
// Get day: sunday is 0, monday is 1. We move everything so that monday == 0
values[(value.startDate.getDay() + 6) % 7].push(value);
}
return values;
}
private static getMonday(d) {
d = new Date(d);
const day = d.getDay();
const diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
return new Date(d.setDate(diff));
}
InnerRender(): string | BaseUIElement {
const today = new Date();
today.setHours(0, 0, 0, 0);
const lastMonday = OpeningHoursVisualization.getMonday(today);
const nextSunday = new Date(lastMonday);
nextSunday.setDate(nextSunday.getDate() + 7);
const tags = this._source.data;
if (tags._country === undefined) {
return "Loading country information...";
}
let oh = null;
try {
// noinspection JSPotentiallyInvalidConstructorUsage
oh = new opening_hours(tags[this._key], {
lat: tags._lat,
lon: tags._lon,
address: {
country_code: tags._country
}
}, {tag_key: this._key});
} catch (e) {
console.log(e);
return new Combine([Translations.t.general.opening_hours.error_loading,
State.state?.osmConnection?.userDetails?.data?.csCount >= Constants.userJourney.tagsVisibleAndWikiLinked ?
`<span class='subtle'>${e}</span>`
: ""
]);
}
if (!oh.getState() && !oh.getUnknown()) {
// POI is currently closed
const nextChange: Date = oh.getNextChange();
if (
// Shop isn't gonna open anymore in this timerange
nextSunday < nextChange
// And we are already in the weekend to show next week
&& (today.getDay() == 0 || today.getDay() == 6)
) {
// We mover further along
lastMonday.setDate(lastMonday.getDate() + 7);
nextSunday.setDate(nextSunday.getDate() + 7);
}
}
// ranges[0] are all ranges for monday
const ranges = OpeningHoursVisualization.GetRanges(oh, lastMonday, nextSunday);
if (ranges.map(r => r.length).reduce((a, b) => a + b, 0) == 0) {
// Closed!
const opensAtDate = oh.getNextChange();
if (opensAtDate === undefined) {
const comm = oh.getComment() ?? oh.getUnknown();
if (!!comm) {
return new FixedUiElement(comm).SetClass("ohviz-closed");
}
if (oh.getState()) {
return Translations.t.general.opening_hours.open_24_7.SetClass("ohviz-closed")
}
return Translations.t.general.opening_hours.closed_permanently.SetClass("ohviz-closed")
}
const moment = `${opensAtDate.getDate()}/${opensAtDate.getMonth() + 1} ${OH.hhmm(opensAtDate.getHours(), opensAtDate.getMinutes())}`
return Translations.t.general.opening_hours.closed_until.Subs({date: moment}).SetClass("ohviz-closed")
}
const isWeekstable = oh.isWeekStable();
let [changeHours, changeHourText] = OpeningHoursVisualization.allChangeMoments(ranges);
// By default, we always show the range between 8 - 19h, in order to give a stable impression
// Ofc, a bigger range is used if needed
const earliestOpen = Math.min(8 * 60 * 60, ...changeHours);
let latestclose = Math.max(...changeHours);
// We always make sure there is 30m of leeway in order to give enough room for the closing entry
latestclose = Math.max(19 * 60 * 60, latestclose + 30 * 60)
const rows: BaseUIElement[] = [];
const availableArea = latestclose - earliestOpen;
// @ts-ignore
const now = (100 * (((new Date() - today) / 1000) - earliestOpen)) / availableArea;
let header: BaseUIElement[] = [];
if (now >= 0 && now <= 100) {
header.push(new FixedUiElement("").SetStyle(`left:${now}%;`).SetClass("ohviz-now"))
}
for (const changeMoment of changeHours) {
const offset = 100 * (changeMoment - earliestOpen) / availableArea;
if (offset < 0 || offset > 100) {
continue;
}
const el = new FixedUiElement("").SetStyle(`left:${offset}%;`).SetClass("ohviz-line");
header.push(el);
}
for (let i = 0; i < changeHours.length; i++) {
let changeMoment = changeHours[i];
const offset = 100 * (changeMoment - earliestOpen) / availableArea;
if (offset < 0 || offset > 100) {
continue;
}
const el = new FixedUiElement(
`<div style='margin-top: ${i % 2 == 0 ? '1.5em;' : "1%"}'>${changeHourText[i]}</div>`
)
.SetStyle(`left:${offset}%`)
.SetClass("ohviz-time-indication");
header.push(el);
}
rows.push(new Combine([`<td width="5%">&NonBreakingSpace;</td>`,
`<td style="position:relative;height:2.5em;">`,
new Combine(header), `</td>`]));
for (let i = 0; i < 7; i++) {
const dayRanges = ranges[i];
const isToday = (new Date().getDay() + 6) % 7 === i;
let weekday = OpeningHoursVisualization.weekdays[i];
let dateToShow = ""
if (!isWeekstable) {
const day = new Date(lastMonday)
day.setDate(day.getDate() + i);
dateToShow = "" + day.getDate() + "/" + (day.getMonth() + 1);
}
let innerContent: (string | BaseUIElement)[] = [];
// Add the lines
for (const changeMoment of changeHours) {
const offset = 100 * (changeMoment - earliestOpen) / availableArea;
innerContent.push(new FixedUiElement("").SetStyle(`left:${offset}%;`).SetClass("ohviz-line"))
}
// Add the actual ranges
for (const range of dayRanges) {
if (!range.isOpen && !range.isSpecial) {
innerContent.push(
new FixedUiElement(range.comment ?? dateToShow).SetClass("ohviz-day-off"))
continue;
}
const startOfDay: Date = new Date(range.startDate);
startOfDay.setHours(0, 0, 0, 0);
// @ts-ignore
const startpoint = (range.startDate - startOfDay) / 1000 - earliestOpen;
// @ts-ignore
const width = (100 * (range.endDate - range.startDate) / 1000) / (latestclose - earliestOpen);
const startPercentage = (100 * startpoint / availableArea);
innerContent.push(
new FixedUiElement(range.comment ?? dateToShow).SetStyle(`left:${startPercentage}%; width:${width}%`).SetClass("ohviz-range"))
}
// Add line for 'now'
if (now >= 0 && now <= 100) {
innerContent.push(new FixedUiElement("").SetStyle(`left:${now}%;`).SetClass("ohviz-now"))
}
let clss = ""
if (isToday) {
clss = "ohviz-today"
}
rows.push(new Combine(
[`<td class="ohviz-weekday ${clss}">${weekday}</td>`,
`<td style="position:relative;" class="${clss}">`,
...innerContent,
`</td>`]))
}
return new Combine([
"<table class='ohviz' style='width:100%; word-break: normal; word-wrap: normal'>",
...rows.map(el => new Combine(["<tr>" ,el , "</tr>"])),
"</table>"
]).SetClass("ohviz-container");
}
private static allChangeMoments(ranges: {
isOpen: boolean,
isSpecial: boolean,
comment: string,
startDate: Date,
endDate: Date
}[][]): [number[], string[]] {
const changeHours: number[] = []
const changeHourText: string[] = [];
const extrachangeHours: number[] = []
const extrachangeHourText: string[] = [];
for (const weekday of ranges) {
for (const range of weekday) {
if (!range.isOpen && !range.isSpecial) {
continue;
}
const startOfDay: Date = new Date(range.startDate);
startOfDay.setHours(0, 0, 0, 0);
// @ts-ignore
const changeMoment: number = (range.startDate - startOfDay) / 1000;
if (changeHours.indexOf(changeMoment) < 0) {
changeHours.push(changeMoment);
changeHourText.push(OH.hhmm(range.startDate.getHours(), range.startDate.getMinutes()))
}
// @ts-ignore
let changeMomentEnd: number = (range.endDate - startOfDay) / 1000;
if (changeMomentEnd >= 24 * 60 * 60) {
if (extrachangeHours.indexOf(changeMomentEnd) < 0) {
extrachangeHours.push(changeMomentEnd);
extrachangeHourText.push(OH.hhmm(range.endDate.getHours(), range.endDate.getMinutes()))
}
} else if (changeHours.indexOf(changeMomentEnd) < 0) {
changeHours.push(changeMomentEnd);
changeHourText.push(OH.hhmm(range.endDate.getHours(), range.endDate.getMinutes()))
}
}
}
changeHourText.sort();
changeHours.sort();
extrachangeHourText.sort();
extrachangeHours.sort();
changeHourText.push(...extrachangeHourText);
changeHours.push(...extrachangeHours);
return [changeHours, changeHourText]
}
}

View file

@ -8,6 +8,9 @@ export interface OpeningHour {
endMinutes: number
}
/**
* Various utilities manipulating opening hours
*/
export class OH {
@ -163,6 +166,12 @@ export class OH {
}
/**
* Gives the number of hours since the start of day.
* E.g.
* startTime({startHour: 9, startMinuts: 15}) == 9.25
* @param oh
*/
public static startTime(oh: OpeningHour): number {
return oh.startHour + oh.startMinutes / 60;
}
@ -348,5 +357,125 @@ export class OH {
return ohs;
}
/*
This function converts a number of ranges (generated by OpeningHours.js) into all the hours of day that a change occurs.
E.g.
Monday, some business is opended from 9:00 till 17:00
Tuesday from 9:30 till 18:00
Wednesday from 9:30 till 12:30
This function will extract all those moments of change and will return 9:00, 9:30, 12:30, 17:00 and 18:00
This list will be sorted
*/
public static allChangeMoments(ranges: {
isOpen: boolean,
isSpecial: boolean,
comment: string,
startDate: Date,
endDate: Date
}[][]): [number[], string[]] {
const changeHours: number[] = []
const changeHourText: string[] = [];
const extrachangeHours: number[] = []
const extrachangeHourText: string[] = [];
for (const weekday of ranges) {
for (const range of weekday) {
if (!range.isOpen && !range.isSpecial) {
continue;
}
const startOfDay: Date = new Date(range.startDate);
startOfDay.setHours(0, 0, 0, 0);
// The number of seconds since the start of the day
// @ts-ignore
const changeMoment: number = (range.startDate - startOfDay) / 1000;
if (changeHours.indexOf(changeMoment) < 0) {
changeHours.push(changeMoment);
changeHourText.push(OH.hhmm(range.startDate.getHours(), range.startDate.getMinutes()))
}
// The number of seconds till between the start of the day and closing
// @ts-ignore
let changeMomentEnd: number = (range.endDate - startOfDay) / 1000;
if (changeMomentEnd >= 24 * 60 * 60) {
if (extrachangeHours.indexOf(changeMomentEnd) < 0) {
extrachangeHours.push(changeMomentEnd);
extrachangeHourText.push(OH.hhmm(range.endDate.getHours(), range.endDate.getMinutes()))
}
} else if (changeHours.indexOf(changeMomentEnd) < 0) {
changeHours.push(changeMomentEnd);
changeHourText.push(OH.hhmm(range.endDate.getHours(), range.endDate.getMinutes()))
}
}
}
// Note that 'changeHours' and 'changeHourText' will be more or less in sync - one is in numbers, the other in 'HH:MM' format.
// But both can be sorted without problem; they'll stay in sync
changeHourText.sort();
changeHours.sort();
extrachangeHourText.sort();
extrachangeHours.sort();
changeHourText.push(...extrachangeHourText);
changeHours.push(...extrachangeHours);
return [changeHours, changeHourText]
}
/*
Calculates when the business is opened (or on holiday) between two dates.
Returns a matrix of ranges, where [0] is a list of ranges when it is opened on monday, [1] is a list of ranges for tuesday, ...
*/
public static GetRanges(oh: any, from: Date, to: Date): ({
isOpen: boolean,
isSpecial: boolean,
comment: string,
startDate: Date,
endDate: Date
}[])[] {
const values = [[], [], [], [], [], [], []];
const start = new Date(from);
// We go one day more into the past, in order to force rendering of holidays in the start of the period
start.setDate(from.getDate() - 1);
const iterator = oh.getIterator(start);
let prevValue = undefined;
while (iterator.advance(to)) {
if (prevValue) {
prevValue.endDate = iterator.getDate() as Date
}
const endDate = new Date(iterator.getDate()) as Date;
endDate.setHours(0, 0, 0, 0)
endDate.setDate(endDate.getDate() + 1);
const value = {
isSpecial: iterator.getUnknown(),
isOpen: iterator.getState(),
comment: iterator.getComment(),
startDate: iterator.getDate() as Date,
endDate: endDate // Should be overwritten by the next iteration
}
prevValue = value;
if (value.comment === undefined && !value.isOpen && !value.isSpecial) {
// simply closed, nothing special here
continue;
}
if (value.startDate < from) {
continue;
}
// Get day: sunday is 0, monday is 1. We move everything so that monday == 0
values[(value.startDate.getDay() + 6) % 7].push(value);
}
return values;
}
}

View file

@ -1,5 +1,4 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import OpeningHoursRange from "./OpeningHoursRange";
import Combine from "../Base/Combine";
import OpeningHoursPickerTable from "./OpeningHoursPickerTable";
@ -8,63 +7,39 @@ import {InputElement} from "../Input/InputElement";
import BaseUIElement from "../BaseUIElement";
export default class OpeningHoursPicker extends InputElement<OpeningHour[]> {
private readonly _ohs: UIEventSource<OpeningHour[]>;
public readonly IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
private readonly _ohs: UIEventSource<OpeningHour[]>;
private readonly _backgroundTable: OpeningHoursPickerTable;
private readonly _weekdays: UIEventSource<BaseUIElement[]> = new UIEventSource<BaseUIElement[]>([]);
constructor(ohs: UIEventSource<OpeningHour[]> = new UIEventSource<OpeningHour[]>([])) {
super();
this._ohs = ohs;
this._backgroundTable = new OpeningHoursPickerTable(this._weekdays, this._ohs);
const self = this;
this._ohs.addCallback(ohs => {
self._ohs.setData(OH.MergeTimes(ohs));
ohs.addCallback(oh => {
ohs.setData(OH.MergeTimes(oh));
})
ohs.addCallbackAndRun(ohs => {
const perWeekday: UIElement[][] = [];
for (let i = 0; i < 7; i++) {
perWeekday[i] = [];
}
for (const oh of ohs) {
const source = new UIEventSource<OpeningHour>(oh)
source.addCallback(_ => {
self._ohs.setData(OH.MergeTimes(self._ohs.data))
})
const r = new OpeningHoursRange(source, this._backgroundTable);
perWeekday[oh.weekday].push(r);
}
for (let i = 0; i < 7; i++) {
self._weekdays.data[i] = new Combine(perWeekday[i]);
}
self._weekdays.ping();
});
this._backgroundTable = new OpeningHoursPickerTable(this._ohs);
this._backgroundTable.ConstructElement()
ohs.ping();
}
InnerRender(): BaseUIElement {
return this._backgroundTable;
}
protected InnerConstructElement(): HTMLElement {
return this._backgroundTable.ConstructElement();
}
GetValue(): UIEventSource<OpeningHour[]> {
return this._ohs
}
IsValid(t: OpeningHour[]): boolean {
return true;
}
protected InnerConstructElement(): HTMLElement {
return this._backgroundTable.ConstructElement();
}
}

View file

@ -3,19 +3,18 @@
* It will genarate the currently selected opening hour.
*/
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import {Utils} from "../../Utils";
import {OpeningHour} from "./OpeningHours";
import {InputElement} from "../Input/InputElement";
import Translations from "../i18n/Translations";
import BaseUIElement from "../BaseUIElement";
import {Translation} from "../i18n/Translation";
import {FixedUiElement} from "../Base/FixedUiElement";
import {VariableUiElement} from "../Base/VariableUIElement";
import Combine from "../Base/Combine";
import OpeningHoursRange from "./OpeningHoursRange";
export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]> {
public readonly IsSelected: UIEventSource<boolean>;
private readonly weekdays: UIEventSource<BaseUIElement[]>;
private readonly _element: HTMLTableElement
public static readonly days: BaseUIElement[] =
public static readonly days: Translation[] =
[
Translations.t.general.weekdays.abbreviations.monday,
Translations.t.general.weekdays.abbreviations.tuesday,
@ -25,60 +24,106 @@ export default class OpeningHoursPickerTable extends InputElement<OpeningHour[]>
Translations.t.general.weekdays.abbreviations.saturday,
Translations.t.general.weekdays.abbreviations.sunday
]
public readonly IsSelected: UIEventSource<boolean>;
private readonly source: UIEventSource<OpeningHour[]>;
/*
These html-elements are an overlay over the table columns and act as a host for the ranges in the weekdays
*/
public readonly weekdayElements : HTMLElement[] = Utils.TimesT(7, () => document.createElement("div"))
private static _nextId = 0;
constructor(weekdays: UIEventSource<BaseUIElement[]>, source?: UIEventSource<OpeningHour[]>) {
constructor(source?: UIEventSource<OpeningHour[]>) {
super();
this.weekdays = weekdays;
this.source = source ?? new UIEventSource<OpeningHour[]>([]);
this.IsSelected = new UIEventSource<boolean>(false);
this.SetStyle("width:100%;height:100%;display:block;");
}
IsValid(t: OpeningHour[]): boolean {
return true;
}
const id = OpeningHoursPickerTable._nextId;
OpeningHoursPickerTable._nextId ++ ;
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>` +
Utils.Times(weekday => `<td id="${id}-timecell-${weekday}-${h}" class="oh-timecell oh-timecell-full oh-timecell-${weekday}"></td>`, 7) +
'</tr><tr>' +
Utils.Times(id => `<td id="${id}-timecell-${id}-${h}-30" class="oh-timecell oh-timecell-half oh-timecell-${id}"></td>`, 7) +
'</tr>';
}
let days = OpeningHoursPickerTable.days.map((day, i) => {
const innerContent = self.weekdays.data[i]?.ConstructElement()?.innerHTML ?? "";
return day.ConstructElement().innerHTML + "<span style='width:100%; display:block; position: relative;'>"+innerContent+"</span>";
}).join("</th><th width='14%'>");
this._element = document.createElement("table")
const el = this._element;
this.SetClass("oh-table")
el.innerHTML =`<tr><th></th><th width='14%'>${days}</th></tr>${rows}`;
GetValue(): UIEventSource<OpeningHour[]> {
return this.source;
}
protected InnerConstructElement(): HTMLElement {
return this._element
}
private InnerUpdate(table: HTMLTableElement) {
const self = this;
if (table === undefined || table === null) {
return;
const table = document.createElement("table")
table.classList.add("oh-table")
const headerRow = document.createElement("tr")
headerRow.appendChild(document.createElement("th"))
for (let i = 0; i < OpeningHoursPickerTable.days.length; i++) {
let weekday = OpeningHoursPickerTable.days[i].Clone();
const cell = document.createElement("th")
cell.style.width = "14%"
cell.appendChild(weekday.ConstructElement())
const fullColumnSpan = this.weekdayElements[i]
fullColumnSpan.classList.add("w-full","h-full","relative")
fullColumnSpan.style.height = "42rem"
const ranges = new VariableUiElement(
this.source.map(ohs => ohs.filter((oh : OpeningHour) => oh.weekday === i))
.map(ohsForToday => {
return new Combine(ohsForToday.map(oh => new OpeningHoursRange(oh, () =>{
this.source.data.splice(this.source.data.indexOf(oh), 1)
this.source.ping()
})))
})
)
fullColumnSpan.appendChild(ranges.ConstructElement())
const fullColumnSpanWrapper = document.createElement("div")
fullColumnSpanWrapper.classList.add("absolute")
fullColumnSpanWrapper.style.zIndex = "10"
fullColumnSpanWrapper.style.width = "13.5%"
fullColumnSpanWrapper.style.pointerEvents = "none"
fullColumnSpanWrapper.appendChild(fullColumnSpan)
cell.appendChild(fullColumnSpanWrapper)
headerRow.appendChild(cell)
}
table.appendChild(headerRow)
const self = this;
for (let h = 0; h < 24; h++) {
const hs = Utils.TwoDigits(h);
const firstCell = document.createElement("td")
firstCell.rowSpan = 2
firstCell.classList.add("oh-left-col", "oh-timecell-full", "border-box","h-2")
firstCell.appendChild(new FixedUiElement(hs + ":00").ConstructElement())
const evenRow = document.createElement("tr")
evenRow.appendChild(firstCell);
for (let weekday = 0; weekday < 7; weekday++) {
const cell = document.createElement("td")
cell.classList.add("oh-timecell", "oh-timecell-full", `oh-timecell-${weekday}`)
evenRow.appendChild(cell)
}
table.appendChild(evenRow)
const oddRow = document.createElement("tr")
for (let weekday = 0; weekday < 7; weekday++) {
const cell = document.createElement("td")
cell.classList.add("oh-timecell", "oh-timecell-half", `oh-timecell-${weekday}`)
oddRow.appendChild(cell)
}
table.appendChild(oddRow)
}
/**** Event handling below ***/
let mouseIsDown = false;
let selectionStart: [number, number] = undefined;
@ -123,6 +168,7 @@ OpeningHoursPickerTable._nextId ++ ;
oh.endMinutes = 0;
}
self.source.data.push(oh);
console.log("Created ", oh)
}
self.source.ping();
@ -149,6 +195,7 @@ OpeningHoursPickerTable._nextId ++ ;
};
let lastSelectionIend, lastSelectionJEnd;
function selectAllBetween(iEnd, jEnd) {
if (lastSelectionIend === iEnd && lastSelectionJEnd === jEnd) {
@ -218,9 +265,9 @@ OpeningHoursPickerTable._nextId ++ ;
jStart <= j + offset && j + offset <= jEnd) {
cell?.classList?.add("oh-timecell-selected")
} else {
cell?.classList?.remove("oh-timecell-selected")
cell?.classList?.remove("oh-timecell-selected")
}
}
@ -263,7 +310,7 @@ OpeningHoursPickerTable._nextId ++ ;
ev.preventDefault();
for (const k in ev.targetTouches) {
const touch = ev.targetTouches[k];
if(touch.clientX === undefined || touch.clientY === undefined){
if (touch.clientX === undefined || touch.clientY === undefined) {
continue;
}
const elUnderTouch = document.elementFromPoint(
@ -287,15 +334,7 @@ OpeningHoursPickerTable._nextId ++ ;
}
}
IsValid(t: OpeningHour[]): boolean {
return true;
}
GetValue(): UIEventSource<OpeningHour[]> {
return this.source;
return table
}
}

View file

@ -1,73 +1,57 @@
/**
* A single opening hours range, shown on top of the OH-picker table
*/
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import {VariableUiElement} from "../Base/VariableUIElement";
import Svg from "../../Svg";
import {Utils} from "../../Utils";
import Combine from "../Base/Combine";
import {OH, OpeningHour} from "./OpeningHours";
import OpeningHoursPickerTable from "./OpeningHoursPickerTable";
import BaseUIElement from "../BaseUIElement";
import {FixedUiElement} from "../Base/FixedUiElement";
export default class OpeningHoursRange extends UIElement {
private _oh: UIEventSource<OpeningHour>;
export default class OpeningHoursRange extends BaseUIElement {
private _oh: OpeningHour;
private readonly _startTime: BaseUIElement;
private readonly _endTime: BaseUIElement;
private readonly _deleteRange: BaseUIElement;
private readonly _tableId: OpeningHoursPickerTable;
private readonly _onDelete: () => void;
constructor(oh: UIEventSource<OpeningHour>, tableId: OpeningHoursPickerTable) {
super(oh);
this._tableId = tableId;
const self = this;
constructor(oh: OpeningHour, onDelete: () => void) {
super();
this._oh = oh;
this._onDelete = onDelete;
this.SetClass("oh-timerange");
oh.addCallbackAndRun(() => {
const el = document.getElementById(this.id) as HTMLElement;
self.InnerUpdate(el);
})
this._deleteRange =
Svg.delete_icon_ui()
.SetClass("oh-delete-range")
.onClick(() => {
oh.data.weekday = undefined;
oh.ping();
});
this._startTime = new VariableUiElement(oh.map(oh => {
return Utils.TwoDigits(oh.startHour) + ":" + Utils.TwoDigits(oh.startMinutes);
})).SetClass("oh-timerange-label")
this._endTime = new VariableUiElement(oh.map(oh => {
return Utils.TwoDigits(oh.endHour) + ":" + Utils.TwoDigits(oh.endMinutes);
})).SetClass("oh-timerange-label")
}
InnerRender(): BaseUIElement {
const oh = this._oh.data;
if (oh === undefined) {
return undefined;
}
InnerConstructElement(): HTMLElement {
const height = this.getHeight();
const oh = this._oh;
const startTime = new FixedUiElement(Utils.TwoDigits(oh.startHour) + ":" + Utils.TwoDigits(oh.startMinutes)).SetClass("oh-timerange-label")
const endTime = new FixedUiElement(Utils.TwoDigits(oh.endHour) + ":" + Utils.TwoDigits(oh.endMinutes)).SetClass("oh-timerange-label")
let content = [this._deleteRange]
const deleteRange =
Svg.delete_icon_ui()
.SetClass("oh-delete-range")
.onClick(() => {
this._onDelete()
});
let content = [deleteRange]
if (height > 2) {
content = [this._startTime, this._deleteRange, this._endTime];
content = [startTime, deleteRange, endTime];
}
return new Combine(content)
.SetClass("oh-timerange-inner")
const el = new Combine(content)
.SetClass("oh-timerange-inner").ConstructElement();
el.style.top = (100 * OH.startTime(oh) / 24) + "%"
el.style.height = (100 * (OH.endTime(oh) - OH.startTime(oh)) / 24) + "%"
return el;
}
private getHeight(): number {
const oh = this._oh.data;
const oh = this._oh;
let endhour = oh.endHour;
if (oh.endHour == 0 && oh.endMinutes == 0) {
@ -76,28 +60,5 @@ export default class OpeningHoursRange extends UIElement {
return (endhour - oh.startHour + ((oh.endMinutes - oh.startMinutes) / 60));
}
protected InnerUpdate(el: HTMLElement) {
if (el == null) {
return;
}
const oh = this._oh.data;
if (oh === undefined) {
return;
}
// The header cell containing monday, tuesday, ...
const table = this._tableId.ConstructElement() as HTMLTableElement;
const bodyRect = document.body.getBoundingClientRect();
const rangeStart = table.rows[1].cells[1].getBoundingClientRect().top - bodyRect.top;
const rangeEnd = table.rows[table.rows.length - 1].cells[1].getBoundingClientRect().bottom - bodyRect.top;
const pixelsPerHour = (rangeEnd - rangeStart) / 24;
el.style.top = (pixelsPerHour * OH.startTime(oh)) + "px";
el.style.height = (pixelsPerHour * (OH.endTime(oh) - OH.startTime(oh))) + "px";
}
}

View file

@ -0,0 +1,292 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import Combine from "../Base/Combine";
import State from "../../State";
import {FixedUiElement} from "../Base/FixedUiElement";
import {OH} from "./OpeningHours";
import Translations from "../i18n/Translations";
import Constants from "../../Models/Constants";
import opening_hours from "opening_hours";
import BaseUIElement from "../BaseUIElement";
import Toggle from "../Input/Toggle";
import {VariableUiElement} from "../Base/VariableUIElement";
import Table from "../Base/Table";
import {Translation} from "../i18n/Translation";
import {UIElement} from "../UIElement";
export default class OpeningHoursVisualization extends UIElement {
private static readonly weekdays: Translation[] = [
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,
]
private readonly _tags: UIEventSource<any>;
private readonly _key: string;
constructor(tags: UIEventSource<any>, key: string) {
super()
this._tags = tags;
this._key = key;
}
InnerRender(): BaseUIElement {
const tags = this._tags;
const key = this._key;
const tagsDirect = tags.data;
const ohTable = new VariableUiElement(tags
.map(tags => tags[key]) // This mapping will absorb all other changes to tags in order to prevent regeneration
.map(ohtext => {
try {
// noinspection JSPotentiallyInvalidConstructorUsage
const oh = new opening_hours(ohtext, {
lat: tagsDirect._lat,
lon: tagsDirect._lon,
address: {
country_code: tagsDirect._country
}
}, {tag_key: this._key});
return OpeningHoursVisualization.CreateFullVisualisation(oh)
} catch (e) {
console.log(e);
return new Combine([Translations.t.general.opening_hours.error_loading,
new Toggle(
new FixedUiElement(e).SetClass("subtle"),
undefined,
State.state?.osmConnection?.userDetails.map(userdetails => userdetails.csCount >= Constants.userJourney.tagsVisibleAndWikiLinked)
)
]);
}
}
))
return new Toggle(
ohTable,
Translations.t.general.loadingCountry.Clone(),
tags.map(tgs => tgs._country !== undefined)
);
}
private static CreateFullVisualisation(oh: any): BaseUIElement {
/** First, we determine which range of dates we want to visualize: this week or next week?**/
const today = new Date();
today.setHours(0, 0, 0, 0);
const lastMonday = OpeningHoursVisualization.getMonday(today);
const nextSunday = new Date(lastMonday);
nextSunday.setDate(nextSunday.getDate() + 7);
if (!oh.getState() && !oh.getUnknown()) {
// POI is currently closed
const nextChange: Date = oh.getNextChange();
if (
// Shop isn't gonna open anymore in this timerange
nextSunday < nextChange
// And we are already in the weekend to show next week
&& (today.getDay() == 0 || today.getDay() == 6)
) {
// We move the range to next week!
lastMonday.setDate(lastMonday.getDate() + 7);
nextSunday.setDate(nextSunday.getDate() + 7);
}
}
/* We calculate the ranges when it is opened! */
const ranges = OH.GetRanges(oh, lastMonday, nextSunday);
/* First, a small sanity check. The business might be permanently closed, 24/7 opened or something other special
* So, we have to handle the case that ranges is completely empty*/
if (ranges.filter(range => range.length > 0).length === 0) {
return OpeningHoursVisualization.ShowSpecialCase(oh).SetClass("p-4 rounded-full block bg-gray-200")
}
/** With all the edge cases handled, we can actually construct the table! **/
return OpeningHoursVisualization.ConstructVizTable(oh, ranges, lastMonday)
}
private static ConstructVizTable(oh: any, ranges: { isOpen: boolean; isSpecial: boolean; comment: string; startDate: Date; endDate: Date }[][],
rangeStart: Date): BaseUIElement {
const isWeekstable: boolean = oh.isWeekStable();
let [changeHours, changeHourText] = OH.allChangeMoments(ranges);
const today = new Date();
today.setHours(0, 0, 0, 0);
// @ts-ignore
const todayIndex = Math.ceil((today - rangeStart) / (1000 * 60 * 60 * 24))
// By default, we always show the range between 8 - 19h, in order to give a stable impression
// Ofc, a bigger range is used if needed
const earliestOpen = Math.min(8 * 60 * 60, ...changeHours);
let latestclose = Math.max(...changeHours);
// We always make sure there is 30m of leeway in order to give enough room for the closing entry
latestclose = Math.max(19 * 60 * 60, latestclose + 30 * 60)
const availableArea = latestclose - earliestOpen;
/*
* The OH-visualisation is a table, consisting of 8 rows and 2 columns:
* The first row is a header row (which is NOT passed as header but just as a normal row!) containing empty for the first column and one object giving all the end times
* The other rows are one for each weekday: the first element showing 'mo', 'tu', ..., the second element containing the bars.
* Note that the bars are actually an embedded <div> spanning the full width, containing multiple sub-elements
* */
const [header, headerHeight] = OpeningHoursVisualization.ConstructHeaderElement(availableArea, changeHours, changeHourText, earliestOpen)
const weekdays = []
const weekdayStyles = []
for (let i = 0; i < 7; i++) {
const day = OpeningHoursVisualization.weekdays[i].Clone();
day.SetClass("w-full h-full block")
const rangesForDay = ranges[i].map(range =>
OpeningHoursVisualization.CreateRangeElem(availableArea, earliestOpen, latestclose, range, isWeekstable)
)
const allRanges = new Combine([
...OpeningHoursVisualization.CreateLinesAtChangeHours(changeHours, availableArea, earliestOpen) ,
...rangesForDay]).SetClass("w-full block");
let extraStyle = ""
if (todayIndex == i) {
extraStyle = "background-color: var(--subtle-detail-color);"
allRanges.SetClass("ohviz-today")
} else if (i >= 5) {
extraStyle = "background-color: rgba(230, 231, 235, 1);"
}
weekdays.push([day, allRanges])
weekdayStyles.push(["padding-left: 0.5em;" + extraStyle, `position: relative;` + extraStyle])
}
return new Table(undefined,
[["&nbsp", header], ...weekdays],
[["width: 5%", `position: relative; height: ${headerHeight}`], ...weekdayStyles]
).SetClass("w-full")
.SetStyle("border-collapse: collapse; word-break; word-break: normal; word-wrap: normal")
}
private static CreateRangeElem(availableArea: number, earliestOpen: number, latestclose: number,
range: { isOpen: boolean; isSpecial: boolean; comment: string; startDate: Date; endDate: Date },
isWeekstable: boolean): BaseUIElement {
const textToShow = range.comment ?? (isWeekstable ? "" : range.startDate.toLocaleDateString());
if (!range.isOpen && !range.isSpecial) {
return new FixedUiElement(textToShow).SetClass("ohviz-day-off")
}
const startOfDay: Date = new Date(range.startDate);
startOfDay.setHours(0, 0, 0, 0);
// @ts-ignore
const startpoint = (range.startDate - startOfDay) / 1000 - earliestOpen;
// @ts-ignore
const width = (100 * (range.endDate - range.startDate) / 1000) / (latestclose - earliestOpen);
const startPercentage = (100 * startpoint / availableArea);
return new FixedUiElement(textToShow).SetStyle(`left:${startPercentage}%; width:${width}%`)
.SetClass("ohviz-range");
}
private static CreateLinesAtChangeHours(changeHours: number[], availableArea: number, earliestOpen: number):
BaseUIElement[] {
const allLines: BaseUIElement[] = []
for (const changeMoment of changeHours) {
const offset = 100 * (changeMoment - earliestOpen) / availableArea;
if (offset < 0 || offset > 100) {
continue;
}
const el = new FixedUiElement("").SetStyle(`left:${offset}%;`).SetClass("ohviz-line");
allLines.push(el);
}
return allLines;
}
/**
* The OH-Visualization header element, a single bar with hours
* @param availableArea
* @param changeHours
* @param changeHourText
* @param earliestOpen
* @constructor
* @private
*/
private static ConstructHeaderElement(availableArea: number, changeHours: number[], changeHourText: string[], earliestOpen: number)
: [BaseUIElement, string] {
let header: BaseUIElement[] = [];
header.push(...OpeningHoursVisualization.CreateLinesAtChangeHours(changeHours, availableArea, earliestOpen))
let showHigher = false;
let showHigherUsed = false;
for (let i = 0; i < changeHours.length; i++) {
let changeMoment = changeHours[i];
const offset = 100 * (changeMoment - earliestOpen) / availableArea;
if (offset < 0 || offset > 100) {
continue;
}
if (i > 0 && ((changeMoment - changeHours[i - 1]) / (60*60)) < 2) {
// Quite close to the previous value
// We alternate the heights
showHigherUsed = true;
showHigher = !showHigher;
} else {
showHigher = false;
}
const el = new Combine([
new FixedUiElement(changeHourText[i])
.SetClass("relative bg-white pl-1 pr-1 h-3 font-sm rounded-xl border-2 border-black border-opacity-50")
.SetStyle("left: -50%; word-break:initial")
])
.SetStyle(`left:${offset}%;margin-top: ${showHigher ? '1.4rem;' : "0.1rem"}`)
.SetClass("block absolute top-0 m-0 h-full box-border ohviz-time-indication");
header.push(el);
}
const headerElem = new Combine(header).SetClass(`w-full absolute block ${showHigherUsed ? "h-16" : "h-8"}`)
.SetStyle("margin-top: -1rem")
const headerHeight = showHigherUsed ? "4rem" : "2rem";
return [headerElem, headerHeight]
}
/*
* Visualizes any special case: e.g. not open for a long time, 24/7 open, ...
* */
private static ShowSpecialCase(oh: any) {
const opensAtDate = oh.getNextChange();
if (opensAtDate === undefined) {
const comm = oh.getComment() ?? oh.getUnknown();
if (!!comm) {
return new FixedUiElement(comm)
}
if (oh.getState()) {
return Translations.t.general.opening_hours.open_24_7.Clone()
}
return Translations.t.general.opening_hours.closed_permanently.Clone()
}
const willOpenAt = `${opensAtDate.getDate()}/${opensAtDate.getMonth() + 1} ${OH.hhmm(opensAtDate.getHours(), opensAtDate.getMinutes())}`
return Translations.t.general.opening_hours.closed_until.Subs({date: willOpenAt})
}
private static getMonday(d) {
d = new Date(d);
const day = d.getDay();
const diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
return new Date(d.setDate(diff));
}
}

View file

@ -18,6 +18,7 @@ export default class EditableTagRendering extends Toggle {
const editMode = new UIEventSource<boolean>(false);
const answer: BaseUIElement = new TagRenderingAnswer(tags, configuration)
answer.SetClass("w-full")
let rendering = answer;
if (configuration.question !== undefined && State.state?.featureSwitchUserbadge?.data) {

View file

@ -109,7 +109,6 @@ export default class ShowDataLayer {
});
}
private postProcessFeature(feature, leafletLayer: L.Layer) {
const layer: LayerConfig = this._layerDict[feature._matching_layer_id];
if (layer === undefined) {
@ -156,7 +155,7 @@ export default class ShowDataLayer {
if (selected === undefined || self._leafletMap.data === undefined) {
return;
}
if (popup.isOpen()) {
if (leafletLayer.getPopup().isOpen()) {
return;
}
if (selected.properties.id === feature.properties.id) {

View file

@ -12,7 +12,7 @@ import ReviewElement from "./Reviews/ReviewElement";
import MangroveReviews from "../Logic/Web/MangroveReviews";
import Translations from "./i18n/Translations";
import ReviewForm from "./Reviews/ReviewForm";
import OpeningHoursVisualization from "./OpeningHours/OhVisualization";
import OpeningHoursVisualization from "./OpeningHours/OpeningHoursVisualization";
import State from "../State";
import {ImageSearcher} from "../Logic/Actors/ImageSearcher";
@ -120,11 +120,7 @@ export default class SpecialVisualizations {
doc: "The tagkey from which the table is constructed."
}],
constr: (state: State, tagSource: UIEventSource<any>, args) => {
let keyname = args[0];
if (keyname === undefined || keyname === "") {
keyname = keyname ?? "opening_hours"
}
return new OpeningHoursVisualization(tagSource, keyname)
return new OpeningHoursVisualization(tagSource, args[0])
}
},

View file

@ -79,8 +79,6 @@ export abstract class UIElement extends BaseUIElement{
}
}
/**
* @deprecated The method should not be used

View file

@ -73,6 +73,14 @@ export class Utils {
return res;
}
public static TimesT<T>(count : number, f: ((i: number) => T)): T[] {
let res : T[] = [];
for (let i = 0; i < count; i++) {
res .push(f(i));
}
return res;
}
static DoEvery(millis: number, f: (() => void)) {
if (Utils.runningFromConsole) {
return;

View file

@ -103,40 +103,31 @@
border-right: 10px solid var(--catch-detail-color) !important;
}
.oh-draggable-header {
background-color: blue;
height: 0.5em;
}
.oh-timerange {
color: var(--catch-detail-color-contrast);
border-radius: 0.5em;
margin-left: 2px;
display: block;
position: absolute;
top: 0;
left: 0;
width: calc(100% - 4px);
margin-left: calc(5% - 1px);
width: 90%;
background: var(--catch-detail-color);
z-index: 1;
box-sizing: border-box;
border: 2px solid var(--catch-detail-color);
overflow: unset;
}
.oh-timerange-inner {
display: flex;
flex-direction: column;
overflow-x: hidden;
justify-content: space-between;
justify-content: center;
align-content: center;
height: 100%;
overflow-y: hidden;
overflow-x: unset;
}
.oh-timerange-inner input {
width: 100%;
box-sizing: border-box;
}
.oh-timerange-inner-small {
display: flex;
flex-direction: row;
@ -144,12 +135,6 @@
height: 100%;
width:100%;
}
.oh-timerange-inner-small input {
width: min-content;
box-sizing: border-box;
}
.oh-delete-range{
width: 1.5em;
height: 1.5em;
@ -162,10 +147,6 @@
max-width: 2em;
}
.oh-timerange-label {
color: white;
}
/**** Opening hours visualization table ****/
@ -190,7 +171,6 @@
.ohviz-today .ohviz-range {
border: 1.5px solid black;
}
.ohviz-day-off {
@ -235,70 +215,12 @@
border-radius: 1em;
}
.ohviz-now {
position: absolute;
top: 0;
margin: 0;
height: 100%;
border: 1px solid black;
box-sizing: border-box
}
.ohviz-line {
position: absolute;
top: 0;
margin: 0;
height: 100%;
border-left: 1px solid #ccc;
border-left: 1px solid #999;
box-sizing: border-box
}
.ohviz-time-indication > div {
position: relative;
background-color: white;
left: -50%;
padding-left: 0.3em;
padding-right: 0.3em;
font-size: smaller;
border-radius: 0.3em;
border: 1px solid #ccc;
word-break: initial;
}
.ohviz-time-indication {
position: absolute;
top: 0;
margin: 0;
height: 100%;
box-sizing: border-box;
}
.ohviz-today {
background-color: var(--subtle-detail-color);
}
.ohviz-weekday {
padding-left: 0.5em;
word-break: normal;
}
.ohviz {
border-collapse: collapse;
}
.ohviz-container {
border: 0.5em solid var(--subtle-detail-color);
border-radius: 1em;
display: block;
}
.ohviz-closed {
padding: 1em;
background-color: #eee;
border-radius: 1em;
display: block;
}

View file

@ -121,6 +121,7 @@
"zoomInToSeeThisLayer": "Zoom in to see this layer",
"title": "Select layers"
},
"loadingCountry": "Determining country...",
"weekdays": {
"abbreviations": {
"monday": "Mon",

27
test.ts
View file

@ -3,21 +3,36 @@ import SpecialVisualizations from "./UI/SpecialVisualizations";
import State from "./State";
import Combine from "./UI/Base/Combine";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import OpeningHoursVisualization from "./UI/OpeningHours/OpeningHoursVisualization";
import OpeningHoursPickerTable from "./UI/OpeningHours/OpeningHoursPickerTable";
import OpeningHoursPicker from "./UI/OpeningHours/OpeningHoursPicker";
import {OH, OpeningHour} from "./UI/OpeningHours/OpeningHours";
import {VariableUiElement} from "./UI/Base/VariableUIElement";
const tagsSource = new UIEventSource({
id:'id',
name:'name',
surface:'asphalt',
id: 'id',
name: 'name',
surface: 'asphalt',
image: "https://i.imgur.com/kX3rl3v.jpg",
"image:1": "https://i.imgur.com/oHAJqMB.jpg",
// "opening_hours":"mo-fr 09:00-18:00",
_country:"be",
"opening_hours": "mo-fr 09:00-18:00",
_country: "be",
})
const state = new State(undefined)
State.state = state
const ohData = new UIEventSource<OpeningHour[]>([{
weekday: 1,
startHour: 10,
startMinutes: 0
, endHour: 12,
endMinutes: 0
}])
new OpeningHoursPicker(ohData).AttachTo("maindiv")
new VariableUiElement(ohData.map(OH.ToString)).AttachTo("extradiv")
/*
const allSpecials = SpecialVisualizations.specialVisualizations.map(spec => {
try{
@ -28,4 +43,4 @@ const allSpecials = SpecialVisualizations.specialVisualizations.map(spec => {
return new FixedUiElement("Could not construct "+spec.funcName+" due to "+e).SetClass("alert")
}
})
new Combine(allSpecials).AttachTo("maindiv")
new Combine(allSpecials).AttachTo("maindiv")*/