From 6563298d16d6efd5534cfa156a8612f0af130419 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 6 Oct 2020 01:37:02 +0200 Subject: [PATCH] More work on the opening hours picker --- InitUiElements.ts | 8 +- Logic/OpeningHours.ts | 195 ++++++++++++++---- Logic/UIEventSource.ts | 4 + State.ts | 5 +- UI/Input/InputElementMap.ts | 2 - UI/Input/OpeningHours/OpeningHoursPicker.ts | 18 +- .../OpeningHours/OpeningHoursPickerTable.ts | 15 +- UI/Input/OpeningHours/OpeningHoursRange.ts | 1 - UI/Input/ValidatedTextField.ts | 14 +- UI/TagRendering.ts | 2 +- index.css | 7 - index.html | 2 +- test.ts | 23 ++- test/Tag.spec.ts | 123 ++++++++++- test/TestHelper.ts | 2 +- 15 files changed, 321 insertions(+), 100 deletions(-) diff --git a/InitUiElements.ts b/InitUiElements.ts index 78332e713..c8d5327a1 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -207,10 +207,12 @@ export class InitUiElements { } - new GeoLocationHandler().AttachTo("geolocate-button"); + new GeoLocationHandler() + .SetStyle(`position:relative;display:block;border: solid 2px #0005;cursor: pointer; z-index: 999; /*Just below leaflets zoom*/background-color: white;border-radius: 5px;width: 43px;height: 43px;`) + .AttachTo("geolocate-button"); State.state.locationControl.ping(); - - + + } diff --git a/Logic/OpeningHours.ts b/Logic/OpeningHours.ts index 18e8d5e08..3f085c7e0 100644 --- a/Logic/OpeningHours.ts +++ b/Logic/OpeningHours.ts @@ -8,7 +8,7 @@ export interface OpeningHour { endMinutes: number } -export class OpeningHourUtils { +export class OH { private static readonly days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"] @@ -23,19 +23,53 @@ export class OpeningHourUtils { } public static ToString(ohs: OpeningHour[]) { - const parts = []; + if (ohs.length == 0) { + return ""; + } + const partsPerWeekday: string [][] = [[], [], [], [], [], [], []]; function hhmm(h, m) { return Utils.TwoDigits(h) + ":" + Utils.TwoDigits(m); } for (const oh of ohs) { - parts.push( - OpeningHourUtils.days[oh.weekday] + " " + hhmm(oh.startHour, oh.startMinutes) + "-" + hhmm(oh.endHour, oh.endMinutes) - ) + partsPerWeekday[oh.weekday].push(hhmm(oh.startHour, oh.startMinutes) + "-" + hhmm(oh.endHour, oh.endMinutes)); } - return parts.join("; ")+";" + const stringPerWeekday = partsPerWeekday.map(parts => parts.sort().join(", ")); + + const rules = []; + + let rangeStart = 0; + let rangeEnd = 0; + + function pushRule(){ + const rule = stringPerWeekday[rangeStart]; + if(rule === ""){ + return; + } + if (rangeStart == (rangeEnd - 1)) { + rules.push( + `${OH.days[rangeStart]} ${rule}` + ); + } else { + rules.push( + `${OH.days[rangeStart]}-${OH.days[rangeEnd-1]} ${rule}` + ); + } + } + + for (; rangeEnd < 7; rangeEnd++) { + + if (stringPerWeekday[rangeStart] != stringPerWeekday[rangeEnd]) { + pushRule(); + rangeStart = rangeEnd + } + + } + pushRule(); + + return rules.join("; ") + ";" } /** @@ -62,32 +96,32 @@ export class OpeningHourUtils { continue } - if (OpeningHourUtils.startTimeLiesInRange(maybeAdd, guard) && OpeningHourUtils.endTimeLiesInRange(maybeAdd, guard)) { + if (OH.startTimeLiesInRange(maybeAdd, guard) && OH.endTimeLiesInRange(maybeAdd, guard)) { // Guard fully covers 'maybeAdd': we can safely ignore maybeAdd doAddEntry = false; break; } - if (OpeningHourUtils.startTimeLiesInRange(guard, maybeAdd) && OpeningHourUtils.endTimeLiesInRange(guard, maybeAdd)) { + if (OH.startTimeLiesInRange(guard, maybeAdd) && OH.endTimeLiesInRange(guard, maybeAdd)) { // 'maybeAdd' fully covers Guard - the guard is killed newList.splice(i, 1); break; } - if (OpeningHourUtils.startTimeLiesInRange(maybeAdd, guard) || OpeningHourUtils.endTimeLiesInRange(maybeAdd, guard) - || OpeningHourUtils.startTimeLiesInRange(guard, maybeAdd) || OpeningHourUtils.endTimeLiesInRange(guard, maybeAdd)) { + if (OH.startTimeLiesInRange(maybeAdd, guard) || OH.endTimeLiesInRange(maybeAdd, guard) + || OH.startTimeLiesInRange(guard, maybeAdd) || OH.endTimeLiesInRange(guard, maybeAdd)) { // At this point, the maybeAdd overlaps the guard: we should extend the guard and retest it newList.splice(i, 1); let startHour = guard.startHour; let startMinutes = guard.startMinutes; - if(OpeningHourUtils.startTime(maybeAdd)OpeningHourUtils.endTime(guard)){ + if (OH.endTime(maybeAdd) > OH.endTime(guard)) { endHour = maybeAdd.endHour; endMinutes = maybeAdd.endMinutes; } @@ -130,51 +164,128 @@ export class OpeningHourUtils { } public static startTimeLiesInRange(checked: OpeningHour, mightLieIn: OpeningHour) { - return OpeningHourUtils.startTime(mightLieIn) <= OpeningHourUtils.startTime(checked) && - OpeningHourUtils.startTime(checked) <= OpeningHourUtils.endTime(mightLieIn) + return OH.startTime(mightLieIn) <= OH.startTime(checked) && + OH.startTime(checked) <= OH.endTime(mightLieIn) } public static endTimeLiesInRange(checked: OpeningHour, mightLieIn: OpeningHour) { - return OpeningHourUtils.startTime(mightLieIn) <= OpeningHourUtils.endTime(checked) && - OpeningHourUtils.endTime(checked) <= OpeningHourUtils.endTime(mightLieIn) + return OH.startTime(mightLieIn) <= OH.endTime(checked) && + OH.endTime(checked) <= OH.endTime(mightLieIn) } - static Parse(str: string) { - if (str === undefined || str === "") { + private static parseHHMM(hhmm: string): { hours: number, minutes: number } { + const spl = hhmm.trim().split(":"); + return {hours: Number(spl[0].trim()), minutes: Number(spl[1].trim())}; + } + + private static parseHHMMRange(hhmmhhmm: string): { + startHour: number, + startMinutes: number, + endHour: number, + endMinutes: number + } { + const timings = hhmmhhmm.split("-"); + const start = OH.parseHHMM(timings[0]) + const end = OH.parseHHMM(timings[1]); + return { + startHour: start.hours, + startMinutes: start.minutes, + endHour: end.hours, + endMinutes: end.minutes + } + } + + private static ParseHhmmRanges(hhmms: string): { + startHour: number, + startMinutes: number, + endHour: number, + endMinutes: number + }[] { + return hhmms.split(",") + .map(s => s.trim()) + .filter(str => str !== "") + .map(OH.parseHHMMRange) + } + + private static ParseWeekday(weekday: string): number { + return OH.daysIndexed[weekday.trim().toLowerCase()]; + } + + private static ParseWeekdayRange(weekdays: string): number[] { + const split = weekdays.split("-"); + if (split.length == 1) { + return [OH.ParseWeekday(weekdays)]; + } else if (split.length == 2) { + let start = OH.ParseWeekday(split[0]); + let end = OH.ParseWeekday(split[1]); + let range = []; + for (let i = start; i <= end; i++) { + range.push(i); + } + return range; + } else { + throw "Invalid format: " + weekdays + " is not a weekdays range" + } + } + + private static ParseWeekdayRanges(weekdays: string): number[] { + let ranges = []; + let split = weekdays.split(","); + for (const weekday of split) { + ranges.push(...OH.ParseWeekdayRange(weekday)); + } + return ranges; + } + + private static multiply(weekdays: number[], timeranges: { startHour: number, startMinutes: number, endHour: number, endMinutes: number }[]) { + const ohs: OpeningHour[] = [] + for (const timerange of timeranges) { + for (const weekday of weekdays) { + ohs.push({ + weekday: weekday, + startHour: timerange.startHour, startMinutes: timerange.startMinutes, + endHour: timerange.endHour, endMinutes: timerange.endMinutes, + }); + } + } + return ohs; + } + + public static ParseRule(rule: string): OpeningHour[] { + const split = rule.trim().replace(/, */g, ",").split(" "); + if (split.length == 1) { + // First, try to parse this rule as a rule without weekdays + let timeranges = OH.ParseHhmmRanges(rule); + let weekdays = [0, 1, 2, 3, 4, 5, 6]; + return OH.multiply(weekdays, timeranges); + } + + if (split.length == 2) { + const weekdays = OH.ParseWeekdayRanges(split[0]); + const timeranges = OH.ParseHhmmRanges(split[1]); + return OH.multiply(weekdays, timeranges); + } + throw `Could not parse rule: ${rule} has ${split.length} parts (expected one or two)`; + } + + + static Parse(rules: string) { + if (rules === undefined || rules === "") { return [] } - const parts = str.toLowerCase().split(";"); const ohs = [] - function parseTime(hhmm) { - const spl = hhmm.trim().split(":"); - return [Number(spl[0].trim()), Number(spl[1].trim())] - } + const split = rules.split(";"); - for (const part of parts) { - if(part === ""){ + for (const rule of split) { + if(rule === ""){ continue; } try { - - const partSplit = part.trim().split(" "); - const weekday = OpeningHourUtils.daysIndexed[partSplit[0]] - const timings = partSplit[1].split("-"); - const start = parseTime(timings[0]) - const end = parseTime(timings[1]); - - const oh: OpeningHour = { - weekday: weekday, - startHour: start[0], - startMinutes: start[1], - endHour: end[0], - endMinutes: end[1], - } - ohs.push(oh); - + ohs.push(...OH.ParseRule(rule)); } catch (e) { - console.error("Could not parse opening hours part", part, ", skipping it due to ", e) + console.error("Could not parse ", rule, ": ", e) } } diff --git a/Logic/UIEventSource.ts b/Logic/UIEventSource.ts index 18b0cd217..47c48a7cb 100644 --- a/Logic/UIEventSource.ts +++ b/Logic/UIEventSource.ts @@ -9,6 +9,10 @@ export class UIEventSource{ public addCallback(callback: ((latestData: T) => void)): UIEventSource { + if(callback === console.log){ + // This ^^^ actually works! + throw "Don't add console.log directly as a callback - you'll won't be able to find it afterwards. Wrap it in a lambda instead." + } this._callbacks.push(callback); return this; } diff --git a/State.ts b/State.ts index 6c3f55674..ad90d138c 100644 --- a/State.ts +++ b/State.ts @@ -111,9 +111,9 @@ export default class State { * The location as delivered by the GPS */ public currentGPSLocation: UIEventSource<{ - latlng: number, + latlng: {lat:number, lon:number}, accuracy: number - }> = new UIEventSource<{ latlng: number, accuracy: number }>(undefined); + }> = new UIEventSource<{ latlng: {lat:number, lon:number}, accuracy: number }>(undefined); public layoutDefinition: string; public installedThemes: UIEventSource<{ layout: Layout; definition: string }[]>; @@ -139,7 +139,6 @@ export default class State { return ("" + fl).substr(0, 8); }) } - this.zoom = asFloat( QueryParameters.GetQueryParameter("z", "" + layoutToUse.startzoom) .syncWith(LocalStorageSource.Get("zoom"), true)); diff --git a/UI/Input/InputElementMap.ts b/UI/Input/InputElementMap.ts index d2d3ddb65..7a0286b90 100644 --- a/UI/Input/InputElementMap.ts +++ b/UI/Input/InputElementMap.ts @@ -35,8 +35,6 @@ export default class InputElementMap extends InputElement { }), extraSources, x => { return fromX(x); }); - this._value.addCallback(console.log) - this.IsSelected.addCallback(s => console.log("Is selected?", s)) } GetValue(): UIEventSource { diff --git a/UI/Input/OpeningHours/OpeningHoursPicker.ts b/UI/Input/OpeningHours/OpeningHoursPicker.ts index 0c6ef17b4..e482c47e2 100644 --- a/UI/Input/OpeningHours/OpeningHoursPicker.ts +++ b/UI/Input/OpeningHours/OpeningHoursPicker.ts @@ -1,6 +1,6 @@ import {UIElement} from "../../UIElement"; import {InputElement} from "../InputElement"; -import {OpeningHour, OpeningHourUtils} from "../../../Logic/OpeningHours"; +import {OpeningHour, OH} from "../../../Logic/OpeningHours"; import {UIEventSource} from "../../../Logic/UIEventSource"; import OpeningHoursPickerTable from "./OpeningHoursPickerTable"; import OpeningHoursRange from "./OpeningHoursRange"; @@ -17,23 +17,16 @@ export default class OpeningHoursPicker extends InputElement { constructor(ohs: UIEventSource = new UIEventSource([])) { super(); this._ohs = ohs; - this._backgroundTable = new OpeningHoursPickerTable(this._weekdays); + this._backgroundTable = new OpeningHoursPickerTable(this._weekdays, this._ohs); const self = this; - this._backgroundTable.GetValue().addCallback(oh => { - if (oh) { - ohs.data.push(oh); - ohs.ping(); - } - }); this._ohs.addCallback(ohs => { - self._ohs.setData(OpeningHourUtils.MergeTimes(ohs)); + self._ohs.setData(OH.MergeTimes(ohs)); }) - ohs.addCallback(ohs => { + ohs.addCallbackAndRun(ohs => { const perWeekday: UIElement[][] = []; - for (let i = 0; i < 7; i++) { perWeekday[i] = []; } @@ -41,7 +34,7 @@ export default class OpeningHoursPicker extends InputElement { for (const oh of ohs) { const source = new UIEventSource(oh) source.addCallback(_ => { - self._ohs.setData(OpeningHourUtils.MergeTimes(self._ohs.data)) + self._ohs.setData(OH.MergeTimes(self._ohs.data)) }) const r = new OpeningHoursRange(source); perWeekday[oh.weekday].push(r); @@ -52,7 +45,6 @@ export default class OpeningHoursPicker extends InputElement { } self._weekdays.ping(); - }); } diff --git a/UI/Input/OpeningHours/OpeningHoursPickerTable.ts b/UI/Input/OpeningHours/OpeningHoursPickerTable.ts index 202e39e23..0e03a650e 100644 --- a/UI/Input/OpeningHours/OpeningHoursPickerTable.ts +++ b/UI/Input/OpeningHours/OpeningHoursPickerTable.ts @@ -8,19 +8,19 @@ import {UIElement} from "../../UIElement"; * This is the base-table which is selectable by hovering over it. * It will genarate the currently selected opening hour. */ -export default class OpeningHoursPickerTable extends InputElement { +export default class OpeningHoursPickerTable extends InputElement { public readonly IsSelected: UIEventSource; private readonly weekdays: UIEventSource; public static readonly days = ["Maan", "Din", "Woe", "Don", "Vrij", "Zat", "Zon"]; - private readonly source: UIEventSource; + private readonly source: UIEventSource; - constructor(weekdays: UIEventSource, source?: UIEventSource) { + constructor(weekdays: UIEventSource, source?: UIEventSource) { super(weekdays); this.weekdays = weekdays; - this.source = source ?? new UIEventSource(undefined); + this.source = source ?? new UIEventSource([]); this.IsSelected = new UIEventSource(false); this.SetStyle("width:100%;height:100%;display:block;"); @@ -105,8 +105,9 @@ export default class OpeningHoursPickerTable extends InputElement { oh.endHour = 24; oh.endMinutes = 0; } - self.source.setData(oh); + self.source.data.push(oh); } + self.source.ping(); // Clear the highlighting for (let i = 1; i < table.rows.length; i++) { @@ -229,11 +230,11 @@ export default class OpeningHoursPickerTable extends InputElement { } - IsValid(t: OpeningHour): boolean { + IsValid(t: OpeningHour[]): boolean { return true; } - GetValue(): UIEventSource { + GetValue(): UIEventSource { return this.source; } diff --git a/UI/Input/OpeningHours/OpeningHoursRange.ts b/UI/Input/OpeningHours/OpeningHoursRange.ts index 9f1c4ac96..b70321f7c 100644 --- a/UI/Input/OpeningHours/OpeningHoursRange.ts +++ b/UI/Input/OpeningHours/OpeningHoursRange.ts @@ -26,7 +26,6 @@ export default class OpeningHoursRange extends UIElement { self.InnerUpdate(el); }) - this._deleteRange = new FixedUiElement("") .SetClass("oh-delete-range") .onClick(() => { diff --git a/UI/Input/ValidatedTextField.ts b/UI/Input/ValidatedTextField.ts index 4ea312605..6e3d9e48c 100644 --- a/UI/Input/ValidatedTextField.ts +++ b/UI/Input/ValidatedTextField.ts @@ -9,7 +9,7 @@ import {UIEventSource} from "../../Logic/UIEventSource"; import CombinedInputElement from "./CombinedInputElement"; import SimpleDatePicker from "./SimpleDatePicker"; import OpeningHoursPicker from "./OpeningHours/OpeningHoursPicker"; -import {OpeningHour, OpeningHourUtils} from "../../Logic/OpeningHours"; +import {OpeningHour, OH} from "../../Logic/OpeningHours"; interface TextFieldDef { name: string, @@ -148,15 +148,17 @@ export default class ValidatedTextField { "opening_hours", "Has extra elements to easily input when a POI is opened", (s, country) => true, // TODO - str => str, // TODO reformat with opening_hours.js + str => str, (value) => { - const input = new InputElementMap(new OpeningHoursPicker(), + + const sourceMapped = value.map(OH.Parse, [], OH.ToString); + + const input = new InputElementMap(new OpeningHoursPicker(sourceMapped), (a, b) => a === b, - ohs => OpeningHourUtils.ToString(ohs), - str => OpeningHourUtils.Parse(str) + ohs => OH.ToString(ohs), + str => OH.Parse(str) ) input.GetValue().addCallback(latest => { - console.log(latest); value.setData(latest); }) return input; diff --git a/UI/TagRendering.ts b/UI/TagRendering.ts index 7febafa6f..d95b45430 100644 --- a/UI/TagRendering.ts +++ b/UI/TagRendering.ts @@ -71,8 +71,8 @@ export class TagRendering extends UIElement implements TagDependantUIElement { }) { super(tags); this.ListenTo(Locale.language); - this.ListenTo(this._questionSkipped); this.ListenTo(this._editMode); + this.ListenTo(this._questionSkipped); this.ListenTo(State.state?.osmConnection?.userDetails); const self = this; diff --git a/index.css b/index.css index e7d20a7e3..868347f7d 100644 --- a/index.css +++ b/index.css @@ -17,13 +17,6 @@ body { position: absolute; bottom: 25px; right: 50px; - z-index: 999; /*Just below leaflets zoom*/ - background-color: white; - border-radius: 5px; - border: solid 2px #0005; - cursor: pointer; - width: 43px; - height: 43px; } #geolocate-button img { diff --git a/index.html b/index.html index d353b3122..ec97707f4 100644 --- a/index.html +++ b/index.html @@ -58,7 +58,7 @@
Loading MapComplete, hang on...
-
+
diff --git a/test.ts b/test.ts index c4a5fea05..f37d17ace 100644 --- a/test.ts +++ b/test.ts @@ -1,17 +1,30 @@ //* +import OpeningHoursPicker from "./UI/Input/OpeningHours/OpeningHoursPicker"; +import {VariableUiElement} from "./UI/Base/VariableUIElement"; +import {OH} from "./Logic/OpeningHours"; -import opening_hours from "opening_hours"; +const picker = new OpeningHoursPicker(); +new VariableUiElement(picker.GetValue().map(OH.ToString)).AttachTo("extradiv"); +picker.AttachTo("maindiv"); -const oh =new opening_hours("mo 09:00-17:00;Tu 09:00-17:00;We 09:00-17:00"); -console.log(oh) - /*/ +window.setTimeout(() => { +picker.GetValue().setData([{ + weekday: 1, + startHour: 11, + startMinutes: 0, + endHour: 17, + endMinutes: 0 +}]); + +}, 1000) +/*/ import {Utils} from "./Utils"; import {FixedUiElement} from "./UI/Base/FixedUiElement"; Utils.generateStats((stats) => { - new FixedUiElement(stats).AttachTo('maindiv') + new FixedUiElement(stats).AttachTo('maindiv') }) //*/ \ No newline at end of file diff --git a/test/Tag.spec.ts b/test/Tag.spec.ts index 4c2944d81..713bdaa55 100644 --- a/test/Tag.spec.ts +++ b/test/Tag.spec.ts @@ -1,7 +1,5 @@ import {UIElement} from "../UI/UIElement"; - UIElement.runningFromConsole = true; - import {equal} from "assert"; import Translation from "../UI/i18n/Translation"; import T from "./TestHelper"; @@ -9,11 +7,10 @@ import {FromJSON} from "../Customizations/JSON/FromJSON"; import {And, Tag} from "../Logic/Tags"; import Locale from "../UI/i18n/Locale"; import Translations from "../UI/i18n/Translations"; -import {TagRenderingOptions} from "../Customizations/TagRenderingOptions"; import {UIEventSource} from "../Logic/UIEventSource"; import {TagRendering} from "../UI/TagRendering"; -import {Basemap} from "../Logic/Leaflet/Basemap"; -import {OpeningHour, OpeningHourUtils} from "../Logic/OpeningHours"; +import {OH, OpeningHour} from "../Logic/OpeningHours"; + new T([ @@ -140,7 +137,7 @@ new T([ endMinutes: 0 }; - const merged = OpeningHourUtils.MergeTimes([oh0, oh1]); + const merged = OH.MergeTimes([oh0, oh1]); const r = merged[0]; equal( merged.length, 1); equal(r.startHour,10 ); @@ -165,12 +162,122 @@ new T([ endMinutes: 0 }; - const merged = OpeningHourUtils.MergeTimes([oh0, oh1]); + const merged = OH.MergeTimes([oh0, oh1]); const r = merged[0]; equal( merged.length, 1); equal(r.startHour,10 ); equal(r.endHour, 12) } - ] + ], + ["Parse OH 1",() => { + const rules = OH.ParseRule("11:00-19:00"); + equal(rules.length, 7); + equal(rules[0].weekday, 0); + equal(rules[0].startHour, 11); + equal(rules[3].endHour, 19); + + }], + ["Parse OH 2",() => { + const rules = OH.ParseRule("Mo-Th 11:00-19:00"); + equal(rules.length, 4); + equal(rules[0].weekday, 0); + equal(rules[0].startHour, 11); + equal(rules[3].endHour, 19); + }], + ["JOIN OH 1",() => { + const rules = OH.ToString([ + { + weekday: 0, + endHour: 12, + endMinutes: 0, + startHour: 10, + startMinutes: 0 + }, + { + weekday: 0, + endHour: 17, + endMinutes: 0, + startHour: 13, + startMinutes: 0 + }, + + + { + weekday: 1, + endHour: 17, + endMinutes: 0, + startHour: 13, + startMinutes: 0 + },{ + weekday: 1, + endHour: 12, + endMinutes: 0, + startHour: 10, + startMinutes: 0 + }, + + ]); + equal(rules, "Mo-Tu 10:00-12:00, 13:00-17:00;"); + }], + ["JOIN OH 2",() => { + const rules = OH.ToString([ + + { + weekday: 1, + endHour: 17, + endMinutes: 0, + startHour: 13, + startMinutes: 0 + },{ + weekday: 1, + endHour: 12, + endMinutes: 0, + startHour: 10, + startMinutes: 0 + }, + + ]); + equal(rules, "Tu 10:00-12:00, 13:00-17:00;"); + }], + ["JOIN OH 3",() => { + const rules = OH.ToString([ + + { + weekday: 3, + endHour: 17, + endMinutes: 0, + startHour: 13, + startMinutes: 0 + },{ + weekday: 1, + endHour: 12, + endMinutes: 0, + startHour: 10, + startMinutes: 0 + }, + + ]); + equal(rules, "Tu 10:00-12:00; Th 13:00-17:00;"); + }], + ["JOIN OH 3",() => { + const rules = OH.ToString([ + + { + weekday: 6, + endHour: 17, + endMinutes: 0, + startHour: 13, + startMinutes: 0 + },{ + weekday: 1, + endHour: 12, + endMinutes: 0, + startHour: 10, + startMinutes: 0 + }, + + ]); + equal(rules, "Tu 10:00-12:00; Sucons 13:00-17:00;"); + }] ]); diff --git a/test/TestHelper.ts b/test/TestHelper.ts index 101cabf20..1520b176a 100644 --- a/test/TestHelper.ts +++ b/test/TestHelper.ts @@ -13,7 +13,7 @@ export default class T { if (failures.length == 0) { console.log("All tests done!") } else { - console.warn(failures.length, "tests failedd :(") + console.warn(failures.length, "tests failed :(") console.log("Failed tests: ", failures.join(",")) } }