diff --git a/.gitpod.yml b/.gitpod.yml index d53368529..d7253fb46 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -10,5 +10,5 @@ ports: vscode: extensions: - "esbenp.prettier-vscode" - - "eamodio.gitlens", - - "GitHub.vscode-pull-request-github" \ No newline at end of file + - "eamodio.gitlens" + - "GitHub.vscode-pull-request-github" diff --git a/Docs/Development_deployment.md b/Docs/Development_deployment.md index ab29c60d3..ed18b9625 100644 --- a/Docs/Development_deployment.md +++ b/Docs/Development_deployment.md @@ -72,6 +72,12 @@ To use the WSL in Visual Studio Code: or `userlayout=true#` as [Query parameter](URL_Parameters.md). Note that the shorter URLs ( e.g. `bookcases.html`, `aed.html`, ...) _don't_ exist on the development version. +### Dependencie + +`make` , `python3` `g++` + +(run `nix-env -iA nixos.gnumake nixos.gdc nixos.python3`) + Automatic deployment -------------------- diff --git a/Logic/Actors/GeoLocationHandler.ts b/Logic/Actors/GeoLocationHandler.ts index f000095d8..c7ca5ae56 100644 --- a/Logic/Actors/GeoLocationHandler.ts +++ b/Logic/Actors/GeoLocationHandler.ts @@ -8,7 +8,7 @@ import {BBox} from "../BBox"; import Constants from "../../Models/Constants"; import SimpleFeatureSource from "../FeatureSource/Sources/SimpleFeatureSource"; -export interface GeoLocationPointProperties { +export interface GeoLocationPointProperties { id: "gps", "user:location": "yes", "date": string, diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index ce1c28198..92c3c9999 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -24,6 +24,7 @@ import FullNodeDatabaseSource from "./TiledFeatureSource/FullNodeDatabaseSource" import MapState from "../State/MapState"; import {ElementStorage} from "../ElementStorage"; import {Feature, Geometry} from "@turf/turf"; +import {OsmFeature} from "../../Models/OsmFeature"; /** @@ -338,15 +339,19 @@ export default class FeaturePipeline { } - public GetAllFeaturesWithin(bbox: BBox): Feature[][] { + public GetAllFeaturesWithin(bbox: BBox): OsmFeature[][] { const self = this - const tiles = [] + const tiles: OsmFeature[][] = [] Array.from(this.perLayerHierarchy.keys()) - .forEach(key => tiles.push(...self.GetFeaturesWithin(key, bbox))) + .forEach(key => { + const fetched : OsmFeature[][] = self.GetFeaturesWithin(key, bbox) + tiles.push(...fetched); + }) return tiles; } - public GetAllFeaturesAndMetaWithin(bbox: BBox, layerIdWhitelist?: Set): {features: any[], layer: string}[] { + public GetAllFeaturesAndMetaWithin(bbox: BBox, layerIdWhitelist?: Set): + {features: OsmFeature[], layer: string}[] { const self = this const tiles :{features: any[], layer: string}[]= [] Array.from(this.perLayerHierarchy.keys()) @@ -362,7 +367,11 @@ export default class FeaturePipeline { return tiles; } - public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] { + /** + * Gets all the tiles which overlap with the given BBOX. + * This might imply that extra features might be shown + */ + public GetFeaturesWithin(layerId: string, bbox: BBox): OsmFeature[][] { if (layerId === "*") { return this.GetAllFeaturesWithin(bbox) } diff --git a/Logic/FeatureSource/FeatureSource.ts b/Logic/FeatureSource/FeatureSource.ts index a686377fc..f28d2cde9 100644 --- a/Logic/FeatureSource/FeatureSource.ts +++ b/Logic/FeatureSource/FeatureSource.ts @@ -1,9 +1,11 @@ import {Store, UIEventSource} from "../UIEventSource"; import FilteredLayer from "../../Models/FilteredLayer"; import {BBox} from "../BBox"; +import {Feature, Geometry} from "@turf/turf"; +import {OsmFeature} from "../../Models/OsmFeature"; export default interface FeatureSource { - features: Store<{ feature: any, freshness: Date }[]>; + features: Store<{ feature: OsmFeature, freshness: Date }[]>; /** * Mainly used for debuging */ @@ -28,12 +30,3 @@ export interface FeatureSourceForLayer extends FeatureSource { export interface IndexedFeatureSource extends FeatureSource { readonly containedIds: Store> } - -/** - * A feature source which has some extra data about it's state - */ -export interface FeatureSourceState { - readonly sufficientlyZoomed: Store; - readonly runningQuery: Store; - readonly timeout: Store; -} diff --git a/Logic/FeatureSource/TiledFeatureSource/TileHierarchy.ts b/Logic/FeatureSource/TiledFeatureSource/TileHierarchy.ts index f2e43069d..cd6b3dda7 100644 --- a/Logic/FeatureSource/TiledFeatureSource/TileHierarchy.ts +++ b/Logic/FeatureSource/TiledFeatureSource/TileHierarchy.ts @@ -13,7 +13,7 @@ export default interface TileHierarchy { export class TileHierarchyTools { public static getTiles(hierarchy: TileHierarchy, bbox: BBox): T[] { - const result = [] + const result: T[] = [] hierarchy.loadedTiles.forEach((tile) => { if (tile.bbox.overlapsWith(bbox)) { result.push(tile) diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts index 240312a9b..e758d5546 100644 --- a/Logic/GeoOperations.ts +++ b/Logic/GeoOperations.ts @@ -3,7 +3,7 @@ import {BBox} from "./BBox"; import togpx from "togpx" import Constants from "../Models/Constants"; import LayerConfig from "../Models/ThemeConfig/LayerConfig"; -import {booleanWithin, Coord, Feature, Geometry, MultiPolygon, Polygon, Properties} from "@turf/turf"; +import {AllGeoJSON, booleanWithin, Coord, Feature, Geometry, MultiPolygon, Polygon, Properties} from "@turf/turf"; export class GeoOperations { @@ -29,7 +29,7 @@ export class GeoOperations { * Returns [lon,lat] coordinates * @param feature */ - static centerpointCoordinates(feature: any): [number, number] { + static centerpointCoordinates(feature: AllGeoJSON): [number, number] { return <[number, number]>turf.center(feature).geometry.coordinates; } diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index 0b887bdf7..ff0cde50b 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -159,7 +159,7 @@ export class Changes { const recentLocationPoints = locations.map(ff => ff.feature) .filter(feat => feat.geometry.type === "Point") .filter(feat => { - const visitTime = new Date((feat.properties).date) + const visitTime = new Date((feat.properties).date) // In seconds const diff = (now.getTime() - visitTime.getTime()) / 1000 return diff < Constants.nearbyVisitTime; diff --git a/Logic/Tags/Tag.ts b/Logic/Tags/Tag.ts index 92f470b4f..803b79390 100644 --- a/Logic/Tags/Tag.ts +++ b/Logic/Tags/Tag.ts @@ -13,7 +13,7 @@ export class Tag extends TagsFilter { throw "Invalid key: undefined or empty"; } if (value === undefined) { - throw "Invalid value: value is undefined"; + throw `Invalid value while constructing a Tag with key '${key}': value is undefined`; } if (value === "*") { console.warn(`Got suspicious tag ${key}=* ; did you mean ${key}~* ?`) diff --git a/Models/OsmFeature.ts b/Models/OsmFeature.ts new file mode 100644 index 000000000..4753287ca --- /dev/null +++ b/Models/OsmFeature.ts @@ -0,0 +1,4 @@ +import {Feature, Geometry} from "@turf/turf"; + +export type OsmTags = Record & {id: string} +export type OsmFeature = Feature \ No newline at end of file diff --git a/Models/ThemeConfig/TagRenderingConfig.ts b/Models/ThemeConfig/TagRenderingConfig.ts index 656d880de..0328a9106 100644 --- a/Models/ThemeConfig/TagRenderingConfig.ts +++ b/Models/ThemeConfig/TagRenderingConfig.ts @@ -20,7 +20,7 @@ export interface Mapping { readonly ifnot?: TagsFilter, readonly then: TypedTranslation, readonly icon: string, - readonly iconClass: string + readonly iconClass: string | "small" | "medium" | "large" | "small-height" | "medium-height" | "large-height", readonly hideInAnswer: boolean | TagsFilter readonly addExtraTags: Tag[], readonly searchTerms?: Record diff --git a/UI/Input/SearchableMappingsSelector.ts b/UI/Input/SearchableMappingsSelector.ts index 191230ece..8a414a879 100644 --- a/UI/Input/SearchableMappingsSelector.ts +++ b/UI/Input/SearchableMappingsSelector.ts @@ -57,7 +57,7 @@ class SelfHidingToggle extends UIElement implements InputElement { return true } s = s?.trim()?.toLowerCase() - return searchTerms[Locale.language.data].some(t => t.indexOf(s) >= 0); + return searchTerms[Locale.language.data]?.some(t => t.indexOf(s) >= 0) ?? false; }, [selected, Locale.language]) const self = this; @@ -121,10 +121,15 @@ class SelfHidingToggle extends UIElement implements InputElement { * A searchfield can be used to filter the values */ export class SearchablePillsSelector extends Combine implements InputElement { - private selectedElements: UIEventSource; + private readonly selectedElements: UIEventSource; public readonly someMatchFound: Store; + /** + * + * @param values + * @param options + */ constructor( values: { show: BaseUIElement, value: T, mainTerm: Record, searchTerms?: Record }[], options?: { @@ -188,7 +193,6 @@ export class SearchablePillsSelector extends Combine implements InputElement< }; }) - let somethingShown: Store if (options.selectIfSingle) { let forcedSelection : { value: T, show: SelfHidingToggle } = undefined @@ -203,15 +207,15 @@ export class SearchablePillsSelector extends Combine implements InputElement< } } if (totalShown == 1) { - if (this.selectedElements.data.indexOf(lastShownValue.value) < 0) { - this.selectedElements.setData([lastShownValue.value]) + if (selectedElements.data?.indexOf(lastShownValue.value) < 0) { + selectedElements.setData([lastShownValue.value]) lastShownValue.show.forceSelected.setData(true) forcedSelection = lastShownValue } } else if (forcedSelection != undefined) { forcedSelection?.show?.forceSelected?.setData(false) forcedSelection = undefined; - this.selectedElements.setData([]) + selectedElements.setData([]) } return totalShown > 0 diff --git a/UI/Popup/TagRenderingQuestion.ts b/UI/Popup/TagRenderingQuestion.ts index ed00ceb82..60dab8ab9 100644 --- a/UI/Popup/TagRenderingQuestion.ts +++ b/UI/Popup/TagRenderingQuestion.ts @@ -22,7 +22,7 @@ import BaseUIElement from "../BaseUIElement"; import {DropDown} from "../Input/DropDown"; import InputElementWrapper from "../Input/InputElementWrapper"; import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; -import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"; +import TagRenderingConfig, {Mapping} from "../../Models/ThemeConfig/TagRenderingConfig"; import {Unit} from "../../Models/Unit"; import VariableInputElement from "../Input/VariableInputElement"; import Toggle from "../Input/Toggle"; @@ -32,6 +32,7 @@ import Title from "../Base/Title"; import {OsmConnection} from "../../Logic/Osm/OsmConnection"; import {GeoOperations} from "../../Logic/GeoOperations"; import {SearchablePillsSelector} from "../Input/SearchableMappingsSelector"; +import {OsmTags} from "../../Models/OsmFeature"; /** * Shows the question element. @@ -39,7 +40,7 @@ import {SearchablePillsSelector} from "../Input/SearchableMappingsSelector"; */ export default class TagRenderingQuestion extends Combine { - constructor(tags: UIEventSource & {id: string}>, + constructor(tags: UIEventSource & { id: string }>, configuration: TagRenderingConfig, state?: FeaturePipelineState, options?: { @@ -53,7 +54,7 @@ export default class TagRenderingQuestion extends Combine { const applicableMappingsSrc = Stores.ListStabilized(tags.map(tags => { - const applicableMappings: { if: TagsFilter, icon?: string, then: TypedTranslation, ifnot?: TagsFilter, addExtraTags: Tag[] }[] = [] + const applicableMappings: Mapping[] = [] for (const mapping of configuration.mappings ?? []) { if (mapping.hideInAnswer === true) { continue @@ -142,7 +143,7 @@ export default class TagRenderingQuestion extends Combine { private static GenerateInputElement( state: FeaturePipelineState, configuration: TagRenderingConfig, - applicableMappings: { if: TagsFilter, then: TypedTranslation, icon?: string, ifnot?: TagsFilter, addExtraTags: Tag[], searchTerms?: Record }[], + applicableMappings: Mapping[], applicableUnit: Unit, tagsSource: UIEventSource, feedback: UIEventSource @@ -231,15 +232,84 @@ export default class TagRenderingQuestion extends Combine { } + /** + * + * // Should return the search as freeform value + * const source = new UIEventSource({id: "1234"}) + * const tr = new TagRenderingConfig({ + * id:"test", + * render:"The value is {key}", + * freeform: { + * key:"key" + * }, + * + * mappings: [ + * { + * if:"x=y", + * then:"z", + * searchTerms: { + * "en" : ["z"] + * } + * } + * ] + * }, "test"); + * const selector = TagRenderingQuestion.GenerateSearchableSelector( + * undefined, + * tr, + * tr.mappings, + * source, + * { + * search: new UIEventSource("value") + * } + * ); + * selector.GetValue().data // => new And([new Tag("key","value")]) + * + * // Should return the search as freeform value, even if a previous search matched + * const source = new UIEventSource({id: "1234"}) + * const search = new UIEventSource("") + * const tr = new TagRenderingConfig({ + * id:"test", + * render:"The value is {key}", + * freeform: { + * key:"key" + * }, + * + * mappings: [ + * { + * if:"x=y", + * then:"z", + * searchTerms: { + * "en" : ["z"] + * } + * } + * ] + * }, "test"); + * const selector = TagRenderingQuestion.GenerateSearchableSelector( + * undefined, + * tr, + * tr.mappings, + * source, + * { + * search + * } + * ); + * search.setData("z") + * search.setData("zx") + * selector.GetValue().data // => new And([new Tag("key","zx")]) + */ private static GenerateSearchableSelector( state: FeaturePipelineState, configuration: TagRenderingConfig, - applicableMappings: { if: TagsFilter; ifnot?: TagsFilter, then: TypedTranslation; icon?: string; iconClass?: string, addExtraTags: Tag[], searchTerms?: Record }[], tagsSource: UIEventSource): InputElement { + applicableMappings: Mapping[], + tagsSource: UIEventSource, + options?: { + search: UIEventSource + }): InputElement { const values: { show: BaseUIElement, value: number, mainTerm: Record, searchTerms?: Record }[] = [] for (let i = 0; i < applicableMappings.length; i++) { const mapping = applicableMappings[i]; const tr = mapping.then.Subs(tagsSource.data) - const patchedMapping = <{ iconClass: "small-height", then: TypedTranslation }>{ + const patchedMapping = { ...mapping, iconClass: `small-height`, icon: mapping.icon ?? "./assets/svg/none.svg" @@ -253,7 +323,7 @@ export default class TagRenderingQuestion extends Combine { }) } - const searchValue: UIEventSource = new UIEventSource(undefined) + const searchValue: UIEventSource = options?.search ?? new UIEventSource(undefined) const ff = configuration.freeform let onEmpty: BaseUIElement = undefined if (ff !== undefined) { @@ -266,8 +336,14 @@ export default class TagRenderingQuestion extends Combine { mode: configuration.multiAnswer ? "select-many" : "select-one", searchValue, onNoMatches: onEmpty?.SetClass(classes).SetClass("flex justify-center items-center"), - searchAreaClass: classes + searchAreaClass: classes, }) + const fallbackTag = searchValue.map(s => { + if (s === undefined || ff?.key === undefined) { + return undefined + } + return new Tag(ff.key, s) + }); return new InputElementMap(presetSearch, (x0, x1) => { if (x0 == x1) { @@ -288,7 +364,7 @@ export default class TagRenderingQuestion extends Combine { }, (selected) => { if (ff !== undefined && searchValue.data?.length > 0 && !presetSearch.someMatchFound.data) { - const t = new Tag(ff.key, searchValue.data) + const t = fallbackTag.data; if (ff.addExtraTags) { return new And([t, ...ff.addExtraTags]) } @@ -436,13 +512,7 @@ export default class TagRenderingQuestion extends Combine { private static GenerateMappingElement( state, tagsSource: UIEventSource, - mapping: { - if: TagsFilter, - then: Translation, - addExtraTags: Tag[], - icon?: string, - iconClass?: "small" | "medium" | "large" | "small-height" - }, ifNot?: TagsFilter[]): InputElement { + mapping: Mapping, ifNot?: TagsFilter[]): InputElement { let tagging: TagsFilter = mapping.if; if (ifNot !== undefined) { @@ -459,11 +529,7 @@ export default class TagRenderingQuestion extends Combine { (t0, t1) => t1.shadows(t0)); } - private static GenerateMappingContent(mapping: { - then: Translation, - icon?: string, - iconClass?: "small" | "medium" | "large" | "small-height" | "medium-height" | "large-height" - }, tagsSource: UIEventSource, state: FeaturePipelineState): BaseUIElement { + private static GenerateMappingContent(mapping: Mapping, tagsSource: UIEventSource, state: FeaturePipelineState): BaseUIElement { const text = new SubstitutedTranslation(mapping.then, tagsSource, state) if (mapping.icon === undefined) { return text; diff --git a/assets/layers/kerbs/kerbs.json b/assets/layers/kerbs/kerbs.json index af185c4d4..ad441c8ec 100644 --- a/assets/layers/kerbs/kerbs.json +++ b/assets/layers/kerbs/kerbs.json @@ -164,9 +164,9 @@ "de": "Wie hoch ist der Bordstein?" }, "render": { - "en": "Kerb height: {{kerb:height}}", - "nl": "Stoeprandhoogte: {{kerb:height}}", - "de": "Bordsteinhöhe: {{kerb:height}}" + "en": "Kerb height: {kerb:height}", + "nl": "Stoeprandhoogte: {kerb:height}", + "de": "Bordsteinhöhe: {kerb:height}" }, "freeform": { "key": "kerb:height", diff --git a/assets/layers/parking/parking.json b/assets/layers/parking/parking.json index 3363bbc3c..0e7d24f8c 100644 --- a/assets/layers/parking/parking.json +++ b/assets/layers/parking/parking.json @@ -26,7 +26,142 @@ "es": "Una capa que muestra aparcamientos para coches" }, "tagRenderings": [ - "images" + "images", + { + "id": "parking-type", + "mappings": [ + { + "if": "parking=surface", + "then": { + "en": "This is a surface parking lot", + "nl": "Dit is een bovengronds parkeerterrein" + } + }, + { + "if": "parking=street_side", + "then": { + "en": "This is a parking bay next to a street", + "nl": "Dit is een parkeerplek langs een weg" + } + }, + { + "if": "parking=underground", + "then": { + "en": "This is an underground parking garage", + "nl": "Dit is een ondergrondse parkeergarage" + } + }, + { + "if": "parking=multi-storey", + "then": { + "en": "This is a multi-storey parking garage", + "nl": "Dit is een bovengrondse parkeergarage met meerdere verdiepingen" + } + }, + { + "if": "parking=rooftop", + "then": { + "en": "This is a rooftop parking deck", + "nl": "Dit is een parkeerdek op een dak" + } + }, + { + "if": "parking=lane", + "then": { + "en": "This is a lane for parking on the road", + "nl": "Dit is een strook voor parkeren op de weg" + } + }, + { + "if": "parking=carports", + "then": { + "en": "This is parking covered by carports", + "nl": "Dit is parking overdekt met carports" + } + }, + { + "if": "parking=garage_boxes", + "then": { + "en": "This a parking consisting of garage boxes", + "nl": "Dit is een parking bestaande uit garageboxen" + } + }, + { + "if": "parking=layby", + "then": { + "en": "This is a parking on a layby", + "nl": "Dit is een parkeerplek op een layby" + } + }, + { + "if": "parking=sheds", + "then": { + "en": "This is a parking consisting of sheds", + "nl": "Dit is een parking bestaande uit schuren" + } + } + ], + "question": { + "en": "What kind of parking is this?", + "nl": "Wat voor parking is dit?" + } + }, + { + "id": "capacity-disabled", + "freeform": { + "key": "capacity:disabled", + "type": "pnat", + "placeholder": { + "en": "Amount of parking spots reserved for disabled people", + "nl": "Aantal parkeerplaatsen voor gehandicapten" + } + }, + "mappings": [ + { + "if": "capacity:disabled=yes", + "then": { + "en": "There are disabled parking spots, but it is not known how many", + "nl": "Er zijn parkeerplaatsen voor gehandicapten, maar het is niet bekend hoeveel er zijn" + }, + "hideInAnswer": true + }, + { + "if": "capacity:disabled=no", + "then": { + "en": "There are no disabled parking spots", + "nl": "Er zijn geen parkeerplaatsen voor gehandicapten" + }, + "hideInAnswer": true + } + ], + "question": { + "en": "How many disabled parking spots are there at this parking?", + "nl": "Hoeveel parkeerplaatsen voor gehandicapten zijn er op deze parking?" + }, + "render": { + "en": "There are {capacity:disabled} disabled parking spots", + "nl": "Er zijn {capacity:disabled} parkeerplaatsen voor gehandicapten" + } + }, + { + "id": "capacity", + "freeform": { + "key": "capacity", + "type": "pnat", + "placeholder": { + "en": "Amount of parking spots", + "nl": "Aantal parkeerplaatsen" + } + }, + "question": { + "en": "How many parking spots are there at this parking?", + "nl": "Hoeveel parkeerplaatsen zijn er op deze parking?" + }, + "render": { + "en": "There are {capacity} parking spots", + "nl": "Er zijn {capacity} parkeerplaatsen" + } + } ], "presets": [ { @@ -52,7 +187,7 @@ }, "allowMove": { "enableRelocation": false, - "enableImproveAccuraccy": true + "enableImproveAccuracy": true }, "mapRendering": [ { diff --git a/langs/layers/de.json b/langs/layers/de.json index 2d686ca62..bfe2f47f8 100644 --- a/langs/layers/de.json +++ b/langs/layers/de.json @@ -4122,7 +4122,7 @@ "placeholder": "Höhe des Bordsteins" }, "question": "Wie hoch ist der Bordstein?", - "render": "Bordsteinhöhe: {{kerb:height}}" + "render": "Bordsteinhöhe: {kerb:height}" }, "kerb-type": { "mappings": { diff --git a/langs/layers/en.json b/langs/layers/en.json index 5186d74fb..d0274d74d 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -4193,7 +4193,7 @@ "placeholder": "Height of the kerb" }, "question": "What is the height of this kerb?", - "render": "Kerb height: {{kerb:height}}" + "render": "Kerb height: {kerb:height}" }, "kerb-type": { "mappings": { @@ -4843,6 +4843,65 @@ "title": "a car parking" } }, + "tagRenderings": { + "capacity": { + "freeform": { + "placeholder": "Amount of parking spots" + }, + "question": "How many parking spots are there at this parking?", + "render": "There are {capacity} parking spots" + }, + "capacity-disabled": { + "freeform": { + "placeholder": "Amount of parking spots reserved for disabled people" + }, + "mappings": { + "0": { + "then": "There are disabled parking spots, but it is not known how many" + }, + "1": { + "then": "There are no disabled parking spots" + } + }, + "question": "How many disabled parking spots are there at this parking?", + "render": "There are {capacity:disabled} disabled parking spots" + }, + "parking-type": { + "mappings": { + "0": { + "then": "This is a surface parking lot" + }, + "1": { + "then": "This is a parking bay next to a street" + }, + "2": { + "then": "This is an underground parking garage" + }, + "3": { + "then": "This is a multi-storey parking garage" + }, + "4": { + "then": "This is a rooftop parking deck" + }, + "5": { + "then": "This is a lane for parking on the road" + }, + "6": { + "then": "This is parking covered by carports" + }, + "7": { + "then": "This a parking consisting of garage boxes" + }, + "8": { + "then": "This is a parking on a layby" + }, + "9": { + "then": "This is a parking consisting of sheds" + } + }, + "question": "What kind of parking is this?" + } + }, "title": { "render": "Car parking" } diff --git a/langs/layers/nl.json b/langs/layers/nl.json index db44efd9a..11d154dcd 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -4053,7 +4053,7 @@ "placeholder": "Hoogte van de stoeprand" }, "question": "Hoe hoog is deze stoeprand?", - "render": "Stoeprandhoogte: {{kerb:height}}" + "render": "Stoeprandhoogte: {kerb:height}" }, "kerb-type": { "mappings": { @@ -4535,6 +4535,65 @@ "title": "een parking voor auto's" } }, + "tagRenderings": { + "capacity": { + "freeform": { + "placeholder": "Aantal parkeerplaatsen" + }, + "question": "Hoeveel parkeerplaatsen zijn er op deze parking?", + "render": "Er zijn {capacity} parkeerplaatsen" + }, + "capacity-disabled": { + "freeform": { + "placeholder": "Aantal parkeerplaatsen voor gehandicapten" + }, + "mappings": { + "0": { + "then": "Er zijn parkeerplaatsen voor gehandicapten, maar het is niet bekend hoeveel er zijn" + }, + "1": { + "then": "Er zijn geen parkeerplaatsen voor gehandicapten" + } + }, + "question": "Hoeveel parkeerplaatsen voor gehandicapten zijn er op deze parking?", + "render": "Er zijn {capacity:disabled} parkeerplaatsen voor gehandicapten" + }, + "parking-type": { + "mappings": { + "0": { + "then": "Dit is een bovengronds parkeerterrein" + }, + "1": { + "then": "Dit is een parkeerplek langs een weg" + }, + "2": { + "then": "Dit is een ondergrondse parkeergarage" + }, + "3": { + "then": "Dit is een bovengrondse parkeergarage met meerdere verdiepingen" + }, + "4": { + "then": "Dit is een parkeerdek op een dak" + }, + "5": { + "then": "Dit is een strook voor parkeren op de weg" + }, + "6": { + "then": "Dit is parking overdekt met carports" + }, + "7": { + "then": "Dit is een parking bestaande uit garageboxen" + }, + "8": { + "then": "Dit is een parkeerplek op een layby" + }, + "9": { + "then": "Dit is een parking bestaande uit schuren" + } + }, + "question": "Wat voor parking is dit?" + } + }, "title": { "render": "Parking voor auto's" } diff --git a/package-lock.json b/package-lock.json index 4558b57eb..a7c3cdf0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "leaflet-providers": "^1.13.0", "leaflet-simple-map-screenshoter": "^0.4.4", "libphonenumber": "^0.0.9", - "libphonenumber-js": "^1.7.55", + "libphonenumber-js": "^1.10.8", "lz-string": "^1.4.4", "mangrove-reviews": "^0.1.3", "moment": "^2.29.2", @@ -54,7 +54,6 @@ "papaparse": "^5.3.1", "parcel": "^1.2.4", "prompt-sync": "^4.2.0", - "svg-resizer": "github:vieron/svg-resizer", "tailwindcss": "^2.2.15", "togpx": "^0.5.4", "tslint": "^6.1.3", @@ -4772,14 +4771,6 @@ "simple-swizzle": "^0.2.2" } }, - "node_modules/colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -7024,36 +7015,6 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, - "node_modules/fs-extra": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.8.1.tgz", - "integrity": "sha1-Dld5/7/t9RG8dVWVx/A8BtS0Po0=", - "dependencies": { - "jsonfile": "~1.1.0", - "mkdirp": "0.3.x", - "ncp": "~0.4.2", - "rimraf": "~2.2.0" - } - }, - "node_modules/fs-extra/node_modules/jsonfile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz", - "integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM=" - }, - "node_modules/fs-extra/node_modules/mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)" - }, - "node_modules/fs-extra/node_modules/rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -9177,9 +9138,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.17.tgz", - "integrity": "sha512-ElJki901OynMg1l+evooPH1VyHrECuLqpgc12z2BkK25dFU5lUKTuMHEYV2jXxvtns/PIuJax56cBeoSK7ANow==" + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.8.tgz", + "integrity": "sha512-MGgHrKRGE7sg7y0DikHybRDgTXcYv4HL+WwhDm5UAiChCNb5tcy5OEaU8XTTt5bDBwhZGCJNxoGMVBpZ4RfhIg==" }, "node_modules/lilconfig": { "version": "2.0.3", @@ -9947,14 +9908,6 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, - "node_modules/ncp": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=", - "bin": { - "ncp": "bin/ncp" - } - }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -10076,21 +10029,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, - "node_modules/nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "deprecated": "Package no longer supported. Contact support@npmjs.com for more info.", - "dependencies": { - "colors": "0.5.x", - "underscore": "~1.4.4" - } - }, - "node_modules/nomnom/node_modules/underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=" - }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -13582,17 +13520,6 @@ "node": ">=0.10.0" } }, - "node_modules/shelljs": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", - "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=", - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -14314,30 +14241,6 @@ "node": ">=6.9.5" } }, - "node_modules/svg-resizer": { - "version": "0.0.1", - "resolved": "git+ssh://git@github.com/vieron/svg-resizer.git#00968cb3e7248533ab9451ce7dffa8af288e4f4a", - "license": "MIT", - "dependencies": { - "fs-extra": "~0.8.1", - "lodash": "~2.4.1", - "nomnom": "~1.6.2", - "shelljs": "~0.2.6", - "xml2js": "~0.4.2" - }, - "bin": { - "svg-resizer": "svg-resizer.js" - } - }, - "node_modules/svg-resizer/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "engines": [ - "node", - "rhino" - ] - }, "node_modules/svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", @@ -20595,11 +20498,6 @@ "simple-swizzle": "^0.2.2" } }, - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=" - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -22391,34 +22289,6 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "dev": true }, - "fs-extra": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.8.1.tgz", - "integrity": "sha1-Dld5/7/t9RG8dVWVx/A8BtS0Po0=", - "requires": { - "jsonfile": "~1.1.0", - "mkdirp": "0.3.x", - "ncp": "~0.4.2", - "rimraf": "~2.2.0" - }, - "dependencies": { - "jsonfile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz", - "integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM=" - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" - }, - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" - } - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -24042,9 +23912,9 @@ } }, "libphonenumber-js": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.17.tgz", - "integrity": "sha512-ElJki901OynMg1l+evooPH1VyHrECuLqpgc12z2BkK25dFU5lUKTuMHEYV2jXxvtns/PIuJax56cBeoSK7ANow==" + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.8.tgz", + "integrity": "sha512-MGgHrKRGE7sg7y0DikHybRDgTXcYv4HL+WwhDm5UAiChCNb5tcy5OEaU8XTTt5bDBwhZGCJNxoGMVBpZ4RfhIg==" }, "lilconfig": { "version": "2.0.3", @@ -24635,11 +24505,6 @@ "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", "dev": true }, - "ncp": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", - "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=" - }, "neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -24755,22 +24620,6 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - }, - "dependencies": { - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=" - } - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -27471,11 +27320,6 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, - "shelljs": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", - "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=" - }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -28038,24 +27882,6 @@ "integrity": "sha512-TAAvLNSE3fEhyl/Da19JWfMAdhSXTYeviXsLSoDT1UM76ADj5ndwAPX1FKQEgB/gFMPavOy6tOqfalXKUiXrow==", "optional": true }, - "svg-resizer": { - "version": "git+ssh://git@github.com/vieron/svg-resizer.git#00968cb3e7248533ab9451ce7dffa8af288e4f4a", - "from": "svg-resizer@github:vieron/svg-resizer", - "requires": { - "fs-extra": "~0.8.1", - "lodash": "~2.4.1", - "nomnom": "~1.6.2", - "shelljs": "~0.2.6", - "xml2js": "~0.4.2" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" - } - } - }, "svgo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", diff --git a/package.json b/package.json index 78485fa28..6d91d1aa2 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "leaflet-providers": "^1.13.0", "leaflet-simple-map-screenshoter": "^0.4.4", "libphonenumber": "^0.0.9", - "libphonenumber-js": "^1.7.55", + "libphonenumber-js": "^1.10.8", "lz-string": "^1.4.4", "mangrove-reviews": "^0.1.3", "moment": "^2.29.2",