diff --git a/Customizations/AllKnownLayouts.ts b/Customizations/AllKnownLayouts.ts index 29e978938..71b2dc186 100644 --- a/Customizations/AllKnownLayouts.ts +++ b/Customizations/AllKnownLayouts.ts @@ -47,6 +47,10 @@ export class AllKnownLayouts { let layer = layout.layers[i]; if (typeof (layer) === "string") { layer = layout.layers[i] = FromJSON.sharedLayers.get(layer); + if(layer === undefined){ + console.log("Defined layers are ", FromJSON.sharedLayers.keys()) + throw `Layer ${layer} was not found or defined - probably a type was made` + } } diff --git a/Customizations/JSON/FromJSON.ts b/Customizations/JSON/FromJSON.ts index 2020a2d8a..1701f0a49 100644 --- a/Customizations/JSON/FromJSON.ts +++ b/Customizations/JSON/FromJSON.ts @@ -16,6 +16,7 @@ import * as bike_parking from "../../assets/layers/bike_parking/bike_parking.jso import * as bike_repair_station from "../../assets/layers/bike_repair_station/bike_repair_station.json" import * as birdhides from "../../assets/layers/bird_hide/birdhides.json" import * as nature_reserve from "../../assets/layers/nature_reserve/nature_reserve.json" +import * as bike_cafes from "../../assets/layers/bike_cafe/bike_cafes.json" import {Utils} from "../../Utils"; import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload"; @@ -41,6 +42,7 @@ export class FromJSON { FromJSON.Layer(bike_repair_station), FromJSON.Layer(birdhides), FromJSON.Layer(nature_reserve), + FromJSON.Layer(bike_cafes), ]; for (const layer of sharedLayersList) { diff --git a/Customizations/Layers/BikeCafes.ts b/Customizations/Layers/BikeCafes.ts deleted file mode 100644 index 24a96dc30..000000000 --- a/Customizations/Layers/BikeCafes.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {LayerDefinition} from "../LayerDefinition"; -import FixedText from "../Questions/FixedText"; -import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload"; -import Translations from "../../UI/i18n/Translations"; -import CafeName from "../Questions/bike/CafeName"; -import {And, Or, RegexTag, Tag} from "../../Logic/Tags"; -import {PhoneNumberQuestion} from "../Questions/PhoneNumberQuestion"; -import Website from "../Questions/Website"; -import CafeRepair from "../Questions/bike/CafeRepair"; -import CafeDiy from "../Questions/bike/CafeDiy"; -import CafePump from "../Questions/bike/CafePump"; -import {EmailQuestion} from "../Questions/EmailQuestion"; - - -export default class BikeCafes extends LayerDefinition { - private readonly to = Translations.t.cyclofix.cafe - - constructor() { - super("bikecafe") - this.name = this.to.name - this.icon = "./assets/bike/cafe.svg" - this.overpassFilter = new And([ - new RegexTag(/^amenity$/, /^pub|bar|cafe$/), - new Or([ - new RegexTag(/^service:bicycle:/, /.*/), - new RegexTag(/^pub$/, /^cycling|bicycle$/), - new RegexTag(/^theme$/, /^cycling|bicycle$/), - ]) - ]) - - this.presets = [ - { - title: Translations.t.cyclofix.cafe.title, - tags : [ - new Tag("amenity", "pub"), - new Tag("pub", "cycling"), - ] - } - ] - - this.maxAllowedOverlapPercentage = 10; - - this.minzoom = 13 - this.style = () => ({ - color: "#00bb00", - icon: { - iconUrl: "./assets/bike/cafe.svg", - iconSize: [50, 50], - iconAnchor: [25, 50] - } - }); - this.title = new FixedText(this.to.title) - this.elementsToShow = [ - new ImageCarouselWithUploadConstructor(), - new CafeName(), - new Website("{name}"), - new PhoneNumberQuestion("{name}"), - new EmailQuestion("{name}"), - new CafeRepair(), - new CafeDiy(), - new CafePump() - ] - this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY - } -} \ No newline at end of file diff --git a/Customizations/Layouts/Cyclofix.ts b/Customizations/Layouts/Cyclofix.ts index 4f66595f4..cfcc34f39 100644 --- a/Customizations/Layouts/Cyclofix.ts +++ b/Customizations/Layouts/Cyclofix.ts @@ -3,7 +3,6 @@ import BikeShops from "../Layers/BikeShops"; import Translations from "../../UI/i18n/Translations"; import Combine from "../../UI/Base/Combine"; import BikeOtherShops from "../Layers/BikeOtherShops"; -import BikeCafes from "../Layers/BikeCafes"; export default class Cyclofix extends Layout { @@ -21,8 +20,8 @@ export default class Cyclofix extends Layout { "cyclofix", ["en", "nl", "fr", "gl"], Translations.t.cyclofix.title, - ["bike_repair_station", new BikeShops(), "drinking_water", "bike_parking", new BikeOtherShops(), new BikeCafes(), - // The first of november, we remember our dead + ["bike_repair_station", "bike_cafes", new BikeShops(), "drinking_water", "bike_parking", new BikeOtherShops(), + // The first of november, halloween and the second of november, we remember our dead ...(Cyclofix.RememberTheDead() ? ["ghost_bike"] : [])], 16, 50.8465573, diff --git a/Customizations/Questions/bike/CafeDiy.ts b/Customizations/Questions/bike/CafeDiy.ts deleted file mode 100644 index d82d5252f..000000000 --- a/Customizations/Questions/bike/CafeDiy.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {Tag} from "../../../Logic/Tags"; -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class CafeDiy extends TagRenderingOptions { - constructor() { - const key = 'service:bicycle:diy' - const to = Translations.t.cyclofix.cafe.diy - super({ - question: to.question, - mappings: [ - {k: new Tag(key, "yes"), txt: to.yes}, - {k: new Tag(key, "no"), txt: to.no}, - ] - }); - } -} diff --git a/Customizations/Questions/bike/CafeName.ts b/Customizations/Questions/bike/CafeName.ts deleted file mode 100644 index 5d29bdb6d..000000000 --- a/Customizations/Questions/bike/CafeName.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class CafeName extends TagRenderingOptions { - constructor() { - const to = Translations.t.cyclofix.cafe.qName - super({ - question: to.question, - freeform: { - key: "name", - renderTemplate: to.render, - template: to.template - } - }) - } -} diff --git a/Customizations/Questions/bike/CafePump.ts b/Customizations/Questions/bike/CafePump.ts deleted file mode 100644 index fd748bfaf..000000000 --- a/Customizations/Questions/bike/CafePump.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {Tag} from "../../../Logic/Tags"; -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class CafePump extends TagRenderingOptions { - constructor() { - const key = 'service:bicycle:pump' - const to = Translations.t.cyclofix.cafe.pump - super({ - question: to.question, - mappings: [ - {k: new Tag(key, "yes"), txt: to.yes}, - {k: new Tag(key, "no"), txt: to.no}, - ] - }); - } -} diff --git a/Customizations/Questions/bike/CafeRepair.ts b/Customizations/Questions/bike/CafeRepair.ts deleted file mode 100644 index 74df83c2d..000000000 --- a/Customizations/Questions/bike/CafeRepair.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {Tag} from "../../../Logic/Tags"; -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class CafeRepair extends TagRenderingOptions { - constructor() { - const key = 'service:bicycle:repair' - const to = Translations.t.cyclofix.cafe.repair - super({ - question: to.question, - mappings: [ - {k: new Tag(key, "yes"), txt: to.yes}, - {k: new Tag(key, "no"), txt: to.no} - ] - }); - } -} diff --git a/Customizations/Questions/bike/ParkingCovered.ts b/Customizations/Questions/bike/ParkingCovered.ts deleted file mode 100644 index abbf64f8c..000000000 --- a/Customizations/Questions/bike/ParkingCovered.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Tag } from "../../../Logic/Tags"; -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class ParkingCovered extends TagRenderingOptions { - constructor() { - const key = 'covered' - const to = Translations.t.cyclofix.parking.covered - super({ - priority: 15, - question: to.question.Render(), - mappings: [ - {k: new Tag(key, "yes"), txt: to.yes}, - {k: new Tag(key, "no"), txt: to.no} - ] - }); - } -} diff --git a/Customizations/Questions/bike/ParkingOperator.ts b/Customizations/Questions/bike/ParkingOperator.ts deleted file mode 100644 index ed8988722..000000000 --- a/Customizations/Questions/bike/ParkingOperator.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {Tag, And} from "../../../Logic/Tags"; -import Translations from "../../../UI/i18n/Translations"; -import {TagRenderingOptions} from "../../TagRenderingOptions"; - - -export default class ParkingOperator extends TagRenderingOptions { - constructor() { - const to = Translations.t.cyclofix.parking.operator - super({ - priority: 15, - question: to.question.Render(), - freeform: { - key: "operator", - template: to.template, - renderTemplate: to.render, - placeholder: Translations.t.cyclofix.freeFormPlaceholder - }, - mappings: [ - {k: new Tag("operator", "KU Leuven"), txt: "KU Leuven"}, - {k: new Tag("operator", "Stad Halle"), txt: "Stad Halle"}, - {k: new Tag("operator", "Saint Gilles - Sint Gillis"), txt: "Saint Gilles - Sint Gillis"}, - {k: new Tag("operator", "Jette"), txt: "Jette"}, - {k: new And([new Tag("operator", ""), new Tag("operator:type", "private")]), txt: to.private.Render()} - ] - }); - } -} diff --git a/Logic/Tags.ts b/Logic/Tags.ts index 8ad669a74..a4727f38b 100644 --- a/Logic/Tags.ts +++ b/Logic/Tags.ts @@ -29,7 +29,10 @@ export class RegexTag extends TagsFilter { } asOverpass(): string[] { - return [`['${RegexTag.source(this.key)}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`]; + if (typeof this.key === "string") { + return [`['${this.key}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`]; + } + return [`[~'${this.key.source}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`]; } private static doesMatch(fromTag: string, possibleRegex: string | RegExp): boolean { @@ -68,7 +71,7 @@ export class RegexTag extends TagsFilter { if (typeof this.key === "string") { return `${this.key}${this.invert ? "!" : ""}~${RegexTag.source(this.value)}`; } - return `~${this.key.source}${this.invert ? "!" : ""}~${RegexTag.source(this.value)}` + return `${this.key.source}${this.invert ? "!" : ""}~~${RegexTag.source(this.value)}` } isEquivalent(other: TagsFilter): boolean { diff --git a/State.ts b/State.ts index 91c9ab603..2a5164741 100644 --- a/State.ts +++ b/State.ts @@ -12,7 +12,6 @@ import {LayerUpdater} from "./Logic/LayerUpdater"; import {UIEventSource} from "./Logic/UIEventSource"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {QueryParameters} from "./Logic/Web/QueryParameters"; -import {FromJSON} from "./Customizations/JSON/FromJSON"; /** * Contains the global state: a bunch of UI-event sources @@ -23,7 +22,7 @@ export class State { // The singleton of the global state public static state: State; - public static vNumber = "0.0.7k"; + public static vNumber = "0.0.7l"; // The user journey states thresholds when a new feature gets unlocked public static userJourney = { diff --git a/UI/Input/TextField.ts b/UI/Input/TextField.ts index ec4df9b1a..30e7ff92c 100644 --- a/UI/Input/TextField.ts +++ b/UI/Input/TextField.ts @@ -43,14 +43,14 @@ export class ValidatedTextField { "email": (str) => EmailValidator.validate(str), "url": (str) => str, "phone": (str, country) => { - return parsePhoneNumberFromString(str, country.toUpperCase())?.isValid() ?? false; + return parsePhoneNumberFromString(str, country?.toUpperCase())?.isValid() ?? false; } } public static formatting = { "phone": (str, country) => { console.log("country formatting", country) - return parsePhoneNumberFromString(str, country.toUpperCase()).formatInternational() + return parsePhoneNumberFromString(str, country?.toUpperCase()).formatInternational() } } } diff --git a/UI/i18n/Translations.ts b/UI/i18n/Translations.ts index 6ee51d677..b197b2751 100644 --- a/UI/i18n/Translations.ts +++ b/UI/i18n/Translations.ts @@ -290,90 +290,6 @@ export default class Translations { }), } }, - cafe: { - name: new T({en: "Bike cafe", nl: "Fietscafé", fr: "Café vélo", gl: "Café de ciclistas"}), - title: new T({en: "Bike cafe", nl: "Fietscafé", fr: "Café Vélo", gl: "Café de ciclistas"}), - qName: { - question: new T({ - en: "What is the name of this bike cafe?", - nl: "Wat is de naam van dit fietscafé?", - fr: "Quel est le nom de ce Café vélo", - gl: "Cal é o nome deste café de ciclistas?" - }), - render: new T({ - en: "This bike cafe is called {name}", - nl: "Dit fietscafé heet {name}", - fr: "Ce Café vélo s'appelle {name}", - gl: "Este café de ciclistas chámase {name}" - }), - template: new T({ - en: "This bike cafe is called: $$$", - nl: "Dit fietscafé heet: $$$", - fr: "Ce Café vélo s'appelle $$$", - gl: "Este café de ciclistas chámase: $$$" - }) - }, - repair: { - question: new T({ - en: "Does this bike cafe repair bikes?", - nl: "Verkoopt dit fietscafé fietsen?", - fr: "Est-ce que ce Café vélo répare les vélos?", - gl: "Este café de ciclistas arranxa bicicletas?" - }), - yes: new T({ - en: "This bike cafe repairs bikes", - nl: "Dit fietscafé herstelt fietsen", - fr: "Ce Café vélo répare les vélos", - gl: "Este café de ciclistas arranxa bicicletas" - }), - no: new T({ - en: "This bike cafe doesn't repair bikes", - nl: "Dit fietscafé herstelt geen fietsen", - fr: "Ce Café vélo ne répare pas les vélos", - gl: "Este café de ciclistas non arranxa bicicletas" - }) - }, - pump: { - question: new T({ - en: "Does this bike cafe offer a bike pump for use by anyone?", - nl: "Biedt dit fietscafé een fietspomp aan voor iedereen?", - fr: "Est-ce que ce Café vélo propose une pompe en libre accès", - gl: "Este café de ciclistas ofrece unha bomba de ar para que calquera persoa poida usala?" - }), - yes: new T({ - en: "This bike cafe offers a bike pump for anyone", - nl: "Dit fietscafé biedt geen fietspomp aan voor eender wie", - fr: "Ce Café vélo offre une pompe en libre accès", - gl: "Este café de ciclistas ofrece unha bomba de ar" - }), - no: new T({ - en: "This bike cafe doesn't offer a bike pump for anyone", - nl: "Dit fietscafé biedt een fietspomp aan voor iedereen", - fr: "Ce Café vélo n'offre pas de pompe en libre accès", - gl: "Este café de ciclistas non ofrece unha bomba de ar" - }) - }, - diy: { - question: new T({ - en: "Are there tools here to repair your own bike?", - nl: "Biedt dit fietscafé gereedschap aan om je fiets zelf te herstellen?", - fr: "Est-ce qu'il y a des outils pour réparer soi-même son vélo?", - gl: "Hai ferramentas aquí para arranxar a túa propia bicicleta?" - }), - yes: new T({ - en: "This bike cafe offers tools for DIY repair", - nl: "Dit fietscafé biedt gereedschap aan om je fiets zelf te herstellen", - fr: "Ce Café vélo propose des outils pour réparer son vélo soi-même", - gl: "Hai ferramentas aquí para arranxar a túa propia bicicleta" - }), - no: new T({ - en: "This bike cafe doesn't offer tools for DIY repair", - nl: "Dit fietscafé biedt geen gereedschap aan om je fiets zelf te herstellen", - fr: "Ce Café vélo ne propose pas d'outils pour réparer son vélo soi-même", - gl: "Non hai ferramentas aquí para arranxar a túa propia bicicleta" - }) - } - }, nonBikeShop: { name: new T({ en: "shop that sells/repairs bikes", diff --git a/assets/bike/cafe.svg b/assets/layers/bike_cafe/bike_cafe.svg similarity index 100% rename from assets/bike/cafe.svg rename to assets/layers/bike_cafe/bike_cafe.svg diff --git a/assets/layers/bike_cafe/bike_cafes.json b/assets/layers/bike_cafe/bike_cafes.json new file mode 100644 index 000000000..ee2b388de --- /dev/null +++ b/assets/layers/bike_cafe/bike_cafes.json @@ -0,0 +1,213 @@ +{ + "id": "bike_cafes", + "name": { + "en": "Bike cafe", + "nl": "Fietscafé", + "fr": "Café vélo", + "gl": "Café de ciclistas" + }, + "minzoom": 12, + "overpassTags": { + "and": [ + "amenity~pub|bar|cafe", + { + "#": "Note the double tilde in 'service:bicycle' which interprets the key as regex too", + "or": [ + "pub~cycling|bicycle", + "theme~cycling|bicycle", + "service:bicycle:.*~~*" + ] + } + ] + }, + "title": { + "render": { + "en": "Bike cafe", + "nl": "Fietscafé", + "fr": "Café Vélo", + "gl": "Café de ciclistas" + }, + "mappings": [ + { + "if": "name~*", + "then": { + "en": "Bike cafe {name}", + "nl": "Fietscafé {name}", + "fr": "Café Vélo {name}", + "gl": "Café de ciclistas {name}" + } + } + ] + }, + "description": {}, + "tagRenderings": [ + { + "question": { + "en": "What is the name of this bike cafe?", + "nl": "Wat is de naam van dit fietscafé?", + "fr": "Quel est le nom de ce Café vélo", + "gl": "Cal é o nome deste café de ciclistas?" + }, + "render": { + "en": "This bike cafe is called {name}", + "nl": "Dit fietscafé heet {name}", + "fr": "Ce Café vélo s'appelle {name}", + "gl": "Este café de ciclistas chámase {name}" + }, + "freeform": { + "key": "name" + } + }, + { + "question": { + "en": "Does this bike cafe offer a bike pump for use by anyone?", + "nl": "Biedt dit fietscafé een fietspomp aan voor iedereen?", + "fr": "Est-ce que ce Café vélo propose une pompe en libre accès", + "gl": "Este café de ciclistas ofrece unha bomba de ar para que calquera persoa poida usala?" + }, + "mappings": [ + { + "if": "service:bicycle:pump=yes", + "then": { + "en": "This bike cafe offers a bike pump for anyone", + "nl": "Dit fietscafé biedt een fietspomp aan voor eender wie", + "fr": "Ce Café vélo offre une pompe en libre accès", + "gl": "Este café de ciclistas ofrece unha bomba de ar" + } + }, + { + "if": "service:bicycle:pump=no", + "then": { + "en": "This bike cafe doesn't offer a bike pump for anyone", + "nl": "Dit fietscafé biedt geen fietspomp aan voor iedereen", + "fr": "Ce Café vélo n'offre pas de pompe en libre accès", + "gl": "Este café de ciclistas non ofrece unha bomba de ar" + } + } + ] + }, + { + "question": { + "en": "Are there tools here to repair your own bike?", + "nl": "Biedt dit fietscafé gereedschap aan om je fiets zelf te herstellen?", + "fr": "Est-ce qu'il y a des outils pour réparer soi-même son vélo?", + "gl": "Hai ferramentas aquí para arranxar a túa propia bicicleta?" + }, + "mappings": [ + { + "if": "service:bicycle:diy=yes", + "then": { + "en": "This bike cafe offers tools for DIY repair", + "nl": "Dit fietscafé biedt gereedschap aan om je fiets zelf te herstellen", + "fr": "Ce Café vélo propose des outils pour réparer son vélo soi-même", + "gl": "Hai ferramentas aquí para arranxar a túa propia bicicleta" + } + }, + { + "if": "service:bicycle:diy=no", + "then": { + "en": "This bike cafe doesn't offer tools for DIY repair", + "nl": "Dit fietscafé biedt geen gereedschap aan om je fiets zelf te herstellen", + "fr": "Ce Café vélo ne propose pas d'outils pour réparer son vélo soi-même", + "gl": "Non hai ferramentas aquí para arranxar a túa propia bicicleta" + } + } + ] + }, + { + "question": { + "en": "Does this bike cafe repair bikes?", + "nl": "Herstelt dit fietscafé fietsen?", + "fr": "Est-ce que ce Café vélo répare les vélos?", + "gl": "Este café de ciclistas arranxa bicicletas?" + }, + "mappings": [ + { + "if": "service:bicycle:repair=yes", + "then": { + "en": "This bike cafe repairs bikes", + "nl": "Dit fietscafé herstelt fietsen", + "fr": "Ce Café vélo répare les vélos", + "gl": "Este café de ciclistas arranxa bicicletas" + } + }, + { + "if": "service:bicycle:repair=no", + "then": { + "en": "This bike cafe doesn't repair bikes", + "nl": "Dit fietscafé herstelt geen fietsen", + "fr": "Ce Café vélo ne répare pas les vélos", + "gl": "Este café de ciclistas non arranxa bicicletas" + } + } + ] + }, + { + "question": { + "en": "What is the website of {name}?", + "nl": "Wat is de website van {name}?", + "fr": "Quel est le site internet de {name}?", + "gl": "Cal é a páxina web de {name}?" + }, + "render": { + "en": "{website}", + "nl": "{website}", + "fr": "{website}", + "gl": "{website}" + }, + "freeform": { + "key": "website" + } + }, + { + "question": { + "en": "What is the phone number of {name}?", + "nl": "Wat is het telefoonnummer van {name}?", + "fr": "Quel est le nom de {name}?", + "gl": "Cal é o número de teléfono de {name}?" + }, + "render": "{phone}", + "freeform": { + "key": "phone", + "type": "phone" + } + }, + { + "question": { + "en": "What is the email address of {name}?", + "nl": "Wat is het email-adres van {name}?", + "fr": "Quel est l'adresse email de {name}?", + "gl": "Cal é o enderezo de correo electrónico de {name}?" + }, + "render": "{email}" + } + ], + "hideUnderlayingFeaturesMinPercentage": 0, + "icon": { + "render": "./assets/layers/bike_cafe/bike_cafe.svg" + }, + "width": { + "render": "2" + }, + "iconSize": { + "render": "50,50,bottom" + }, + "color": { + "render": "#694E2D" + }, + "presets": [ + { + "title": { + "en": "Bike cafe", + "nl": "Fietscafé", + "fr": "Café Vélo", + "gl": "Café de ciclistas" + }, + "tags": [ + "amenity=pub", + "pub=cycling" + ] + } + ], + "wayHandling": 2 +} \ No newline at end of file diff --git a/test.ts b/test.ts index 8d34719d9..2f30594df 100644 --- a/test.ts +++ b/test.ts @@ -1,4 +1,3 @@ -import BikeCafes from "./Customizations/Layers/BikeCafes"; import {CheckBoxes} from "./UI/Input/Checkboxes"; import {FixedInputElement} from "./UI/Input/FixedInputElement"; import {VariableUiElement} from "./UI/Base/VariableUIElement";