From d3550fefbe1f719e9c2682c63a77083a9e9c5ad3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Tue, 12 Oct 2021 02:12:45 +0200 Subject: [PATCH] Add multi-apply box/feature, use it in etymology-theme to apply tags onto all segments of the same street --- Docs/CalculatedTags.md | 13 +- Docs/SpecialInputElements.md | 2 +- Docs/SpecialRenderings.md | 22 ++- Docs/TagInfo/mapcomplete_nature.json | 9 + .../mapcomplete_observation_towers.json | 9 + Logic/ExtraFunction.ts | 4 +- Logic/FeatureSource/FeaturePipeline.ts | 3 + Logic/ImageProviders/ImageProvider.ts | 1 - Logic/ImageProviders/WikidataImageProvider.ts | 1 - Logic/MetaTagging.ts | 4 +- Logic/SimpleMetaTagger.ts | 20 ++- UI/Popup/MultiApply.ts | 158 ++++++++++++++++++ UI/SpecialVisualizations.ts | 33 +++- UI/Wikipedia/WikidataPreviewBox.ts | 1 - UI/i18n/Translation.ts | 2 +- assets/layers/etymology/etymology.json | 16 ++ assets/tagRenderings/questions.json | 21 ++- .../toerisme_vlaanderen.json | 2 +- langs/en.json | 3 + langs/layers/en.json | 3 + langs/themes/en.json | 102 +++++------ langs/themes/nl.json | 4 +- 22 files changed, 355 insertions(+), 78 deletions(-) create mode 100644 UI/Popup/MultiApply.ts diff --git a/Docs/CalculatedTags.md b/Docs/CalculatedTags.md index 08083a10f..b9bfe2104 100644 --- a/Docs/CalculatedTags.md +++ b/Docs/CalculatedTags.md @@ -28,6 +28,15 @@ The latitude and longitude of the point (or centerpoint in the case of a way/are +### _layer + + + +The layer-id to which this feature belongs. Note that this might be return any applicable if `passAllFeatures` is defined. + + + + ### _surface, _surface:ha @@ -173,7 +182,7 @@ For example to get all objects which overlap or embed from a layer, use `_contai Given either a list of geojson features or a single layer name, gives the single object which is nearest to the feature. In the case of ways/polygons, only the centerpoint is considered. Returns a single geojson feature or undefined if nothing is found (or not yet laoded) - 0. list of features + 0. list of features or a layer name or '*' to get all features ### closestn @@ -181,7 +190,7 @@ For example to get all objects which overlap or embed from a layer, use `_contai If a 'unique tag key' is given, the tag with this key will only appear once (e.g. if 'name' is given, all features will have a different name) - 0. list of features or layer name + 0. list of features or layer name or '*' to get all features 1. amount of features 2. unique tag key (optional) 3. maxDistanceInMeters (optional) diff --git a/Docs/SpecialInputElements.md b/Docs/SpecialInputElements.md index 957a74db4..3c05b4c87 100644 --- a/Docs/SpecialInputElements.md +++ b/Docs/SpecialInputElements.md @@ -24,7 +24,7 @@ A geographical length in meters (rounded at two points). Will give an extra mini ## wikidata -A wikidata identifier, e.g. Q42 +A wikidata identifier, e.g. Q42. Input helper arguments: [ key: the value of this tag will initialize search (default: name), options: { removePrefixes: string[], removePostfixes: string[] } these prefixes and postfixes will be removed from the initial search value] ## int diff --git a/Docs/SpecialRenderings.md b/Docs/SpecialRenderings.md index f5ca4d6e8..7fff50797 100644 --- a/Docs/SpecialRenderings.md +++ b/Docs/SpecialRenderings.md @@ -14,7 +14,7 @@ name | default | description ------ | --------- | ------------- -image key/prefix | image | The keys given to the images, e.g. if image is given, the first picture URL will be added as image, the second as image:0, the third as image:1, etc... +image key/prefix (multiple values allowed if comma-seperated) | image | The keys given to the images, e.g. if image is given, the first picture URL will be added as image, the second as image:0, the third as image:1, etc... #### Example usage @@ -26,10 +26,11 @@ image key/prefix | image | The keys given to the images, e.g. if { return (features) => ExtraFunction.GetClosestNFeatures(params, feature, features)?.[0]?.feat @@ -132,7 +132,7 @@ export class ExtraFunction { doc: "Given either a list of geojson features or a single layer name, gives the n closest objects which are nearest to the feature (excluding the feature itself). In the case of ways/polygons, only the centerpoint is considered. " + "Returns a list of `{feat: geojson, distance:number}` the empty list if nothing is found (or not yet loaded)\n\n" + "If a 'unique tag key' is given, the tag with this key will only appear once (e.g. if 'name' is given, all features will have a different name)", - args: ["list of features or layer name", "amount of features", "unique tag key (optional)", "maxDistanceInMeters (optional)"] + args: ["list of features or layer name or '*' to get all features", "amount of features", "unique tag key (optional)", "maxDistanceInMeters (optional)"] }, (params, feature) => { diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index ee89ee6aa..a24f18d8c 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -402,6 +402,9 @@ export default class FeaturePipeline { } public GetFeaturesWithin(layerId: string, bbox: BBox): any[][] { + if(layerId === "*"){ + return this.GetAllFeaturesWithin(bbox) + } const requestedHierarchy = this.perLayerHierarchy.get(layerId) if (requestedHierarchy === undefined) { console.warn("Layer ", layerId, "is not defined. Try one of ", Array.from(this.perLayerHierarchy.keys())) diff --git a/Logic/ImageProviders/ImageProvider.ts b/Logic/ImageProviders/ImageProvider.ts index 1dd38c2b7..12e05272e 100644 --- a/Logic/ImageProviders/ImageProvider.ts +++ b/Logic/ImageProviders/ImageProvider.ts @@ -55,7 +55,6 @@ export default abstract class ImageProvider { } seenValues.add(value) this.ExtractUrls(key, value).then(promises => { - console.log("Got ", promises.length, "promises for", value,"by",self.constructor.name) for (const promise of promises ?? []) { if (promise === undefined) { continue diff --git a/Logic/ImageProviders/WikidataImageProvider.ts b/Logic/ImageProviders/WikidataImageProvider.ts index 9c3d6af3e..139201578 100644 --- a/Logic/ImageProviders/WikidataImageProvider.ts +++ b/Logic/ImageProviders/WikidataImageProvider.ts @@ -27,7 +27,6 @@ export class WikidataImageProvider extends ImageProvider { if(entity === undefined){ return [] } - console.log("Entity:", entity) const allImages : Promise[] = [] // P18 is the claim 'depicted in this image' diff --git a/Logic/MetaTagging.ts b/Logic/MetaTagging.ts index 8b7eec75b..83b85f34a 100644 --- a/Logic/MetaTagging.ts +++ b/Logic/MetaTagging.ts @@ -64,12 +64,12 @@ export default class MetaTagging { if(metatag.isLazy){ somethingChanged = true; - metatag.applyMetaTagsOnFeature(feature, freshness) + metatag.applyMetaTagsOnFeature(feature, freshness, layer) }else{ - const newValueAdded = metatag.applyMetaTagsOnFeature(feature, freshness) + const newValueAdded = metatag.applyMetaTagsOnFeature(feature, freshness, layer) /* Note that the expression: * `somethingChanged = newValueAdded || metatag.applyMetaTagsOnFeature(feature, freshness)` * Is WRONG diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index b0e4d50bf..f6c0b5359 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -6,6 +6,7 @@ import Combine from "../UI/Base/Combine"; import BaseUIElement from "../UI/BaseUIElement"; import Title from "../UI/Base/Title"; import {FixedUiElement} from "../UI/Base/FixedUiElement"; +import LayerConfig from "../Models/ThemeConfig/LayerConfig"; const cardinalDirections = { @@ -62,6 +63,20 @@ export default class SimpleMetaTagger { return true; }) ); + private static layerInfo = new SimpleMetaTagger( + { + doc: "The layer-id to which this feature belongs. Note that this might be return any applicable if `passAllFeatures` is defined.", + keys:["_layer"], + includesDates: false, + }, + (feature, freshness, layer) => { + if(feature.properties._layer === layer.id){ + return false; + } + feature.properties._layer = layer.id + return true; + } + ) private static surfaceArea = new SimpleMetaTagger( { keys: ["_surface", "_surface:ha"], @@ -329,6 +344,7 @@ export default class SimpleMetaTagger { ) public static metatags = [ SimpleMetaTagger.latlon, + SimpleMetaTagger.layerInfo, SimpleMetaTagger.surfaceArea, SimpleMetaTagger.lngth, SimpleMetaTagger.canonicalize, @@ -346,7 +362,7 @@ export default class SimpleMetaTagger { public readonly doc: string; public readonly isLazy: boolean; public readonly includesDates: boolean - public readonly applyMetaTagsOnFeature: (feature: any, freshness: Date) => boolean; + public readonly applyMetaTagsOnFeature: (feature: any, freshness: Date, layer: LayerConfig) => boolean; /*** * A function that adds some extra data to a feature @@ -354,7 +370,7 @@ export default class SimpleMetaTagger { * @param f: apply the changes. Returns true if something changed */ constructor(docs: { keys: string[], doc: string, includesDates?: boolean, isLazy?: boolean }, - f: ((feature: any, freshness: Date) => boolean)) { + f: ((feature: any, freshness: Date, layer: LayerConfig) => boolean)) { this.keys = docs.keys; this.doc = docs.doc; this.isLazy = docs.isLazy diff --git a/UI/Popup/MultiApply.ts b/UI/Popup/MultiApply.ts new file mode 100644 index 000000000..30575cdd5 --- /dev/null +++ b/UI/Popup/MultiApply.ts @@ -0,0 +1,158 @@ +import {UIEventSource} from "../../Logic/UIEventSource"; +import BaseUIElement from "../BaseUIElement"; +import Combine from "../Base/Combine"; +import {SubtleButton} from "../Base/SubtleButton"; +import {Changes} from "../../Logic/Osm/Changes"; +import {FixedUiElement} from "../Base/FixedUiElement"; +import Translations from "../i18n/Translations"; +import {VariableUiElement} from "../Base/VariableUIElement"; +import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"; +import {Tag} from "../../Logic/Tags/Tag"; +import {ElementStorage} from "../../Logic/ElementStorage"; +import {And} from "../../Logic/Tags/And"; +import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig"; +import Toggle from "../Input/Toggle"; +import {OsmConnection} from "../../Logic/Osm/OsmConnection"; + + +export interface MultiApplyParams { + featureIds: UIEventSource, + keysToApply: string[], + text: string, + autoapply: boolean, + overwrite: boolean, + tagsSource: UIEventSource, + state: { + changes: Changes, + allElements: ElementStorage, + layoutToUse: LayoutConfig, + osmConnection: OsmConnection + } +} + +class MultiApplyExecutor { + + private readonly originalValues = new Map() + private readonly params: MultiApplyParams; + + private constructor(params: MultiApplyParams) { + this.params = params; + const p = params + + for (const key of p.keysToApply) { + this.originalValues.set(key, p.tagsSource.data[key]) + } + + if (p.autoapply) { + + const self = this; + const relevantValues = p.tagsSource.map(tags => { + const currentValues = p.keysToApply.map(key => tags[key]) + const v = JSON.stringify(currentValues) // By stringifying, we have a very clear ping when they changec + console.log("Values are", v) + return v; + }) + relevantValues.addCallbackD(_ => { + self.applyTaggingOnOtherFeatures() + }) + } + } + + public applyTaggingOnOtherFeatures() { + console.log("Multi-applying changes...") + const featuresToChange = this.params.featureIds.data + const changes = this.params.state.changes + const allElements = this.params.state.allElements + const keysToChange = this.params.keysToApply + const overwrite = this.params.overwrite + const selfTags = this.params.tagsSource.data; + const theme = this.params.state.layoutToUse.id + for (const id of featuresToChange) { + const tagsToApply: Tag[] = [] + const otherFeatureTags = allElements.getEventSourceById(id).data + for (const key of keysToChange) { + const newValue = selfTags[key] + if (newValue === undefined) { + continue + } + const otherValue = otherFeatureTags[key] + if (newValue === otherValue) { + continue;// No changes to be made + } + + if (overwrite) { + tagsToApply.push(new Tag(key, newValue)) + continue; + } + + + if (otherValue === undefined || otherValue === "" || otherValue === this.originalValues.get(key)) { + tagsToApply.push(new Tag(key, newValue)) + } + } + + if (tagsToApply.length == 0) { + continue; + } + + + changes.applyAction( + new ChangeTagAction(id, new And(tagsToApply), otherFeatureTags, { + theme, + changeType: "answer" + })) + } + } + + private static executorCache = new Map() + + public static GetApplicator(id: string, params: MultiApplyParams): MultiApplyExecutor { + if (MultiApplyExecutor.executorCache.has(id)) { + return MultiApplyExecutor.executorCache.get(id) + } + const applicator = new MultiApplyExecutor(params) + MultiApplyExecutor.executorCache.set(id, applicator) + return applicator + } + +} + +export default class MultiApply extends Toggle { + + constructor(params: MultiApplyParams) { + const p = params + const t = Translations.t.multi_apply + + + const featureId = p.tagsSource.data.id + + if (featureId === undefined) { + throw "MultiApply needs a feature id" + } + + const applicator = MultiApplyExecutor.GetApplicator(featureId, params) + + const elems: (string | BaseUIElement)[] = [] + if (p.autoapply) { + elems.push(new Combine([new FixedUiElement(p.text).SetClass("block") ]).SetClass("flex")) + elems.push(new VariableUiElement(p.featureIds.map(featureIds => + t.autoApply.Subs({ + attr_names: p.keysToApply.join(", "), + count: "" + featureIds.length + }))).SetClass("block subtle text-sm")) + } else { + elems.push( + new SubtleButton(undefined, p.text).onClick(() => applicator.applyTaggingOnOtherFeatures()) + ) + } + + + const isShown: UIEventSource = p.state.osmConnection.isLoggedIn.map(loggedIn => { + return loggedIn && p.featureIds.data.length > 0 + }, [p.featureIds]) + super(new Combine(elems), undefined, isShown); + + } + + +} \ No newline at end of file diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index af9a2aa88..3af7df316 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -28,6 +28,7 @@ import Minimap from "./Base/Minimap"; import AllImageProviders from "../Logic/ImageProviders/AllImageProviders"; import WikipediaBox from "./Wikipedia/WikipediaBox"; import SimpleMetaTagger from "../Logic/SimpleMetaTagger"; +import MultiApply from "./Popup/MultiApply"; export interface SpecialVisualization { funcName: string, @@ -484,8 +485,38 @@ There are also some technicalities in your theme to keep in mind: args[2], args[1], tagSource, rewrittenTags, lat, lon, Number(args[3]), state ) } + }, + {funcName: "multi_apply", + docs: "A button to apply the tagging of this object onto a list of other features. This is an advanced feature for which you'll need calculatedTags", + args:[ + {name: "feature_ids", doc: "A JSOn-serialized list of IDs of features to apply the tagging on"}, + {name: "keys", doc: "One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features." }, + {name: "text", doc: "The text to show on the button"}, + {name:"autoapply",doc:"A boolean indicating wether this tagging should be applied automatically if the relevant tags on this object are changed. A visual element indicating the multi_apply is still shown"}, + {name:"overwrite",doc:"If set to 'true', the tags on the other objects will always be overwritten. The default behaviour will be to only change the tags on other objects if they are either undefined or had the same value before the change"} + ], + example: "{multi_apply(_features_with_the_same_name_within_100m, name:etymology:wikidata;name:etymology, Apply etymology information on all nearby objects with the same name)}", + constr: (state, tagsSource, args) => { + const featureIdsKey = args[0] + const keysToApply = args[1].split(";") + const text = args[2] + const autoapply = args[3]?.toLowerCase() === "true" + const overwrite = args[4]?.toLowerCase() === "true" + const featureIds : UIEventSource = tagsSource.map(tags => JSON.parse(tags[featureIdsKey])) + return new MultiApply( + { + featureIds, + keysToApply, + text, + autoapply, + overwrite, + tagsSource, + state + } + ); + + } } - ] static HelpMessage: BaseUIElement = SpecialVisualizations.GenHelpMessage(); diff --git a/UI/Wikipedia/WikidataPreviewBox.ts b/UI/Wikipedia/WikidataPreviewBox.ts index d6682326b..feca815fa 100644 --- a/UI/Wikipedia/WikidataPreviewBox.ts +++ b/UI/Wikipedia/WikidataPreviewBox.ts @@ -53,7 +53,6 @@ export default class WikidataPreviewBox extends VariableUiElement { ]).SetClass("flex"), Wikidata.IdToArticle(wikidata.id) ,true).SetClass("must-link") - console.log(wikidata) let info = new Combine( [ new Combine([Translation.fromMap(wikidata.labels).SetClass("font-bold"), link]).SetClass("flex justify-between"), diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index fd9b1dacd..a4260a772 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -217,7 +217,7 @@ export class Translation extends BaseUIElement { static fromMap(transl: Map) { const translations = {} - transl.forEach((value, key) => { + transl?.forEach((value, key) => { translations[key] = value }) return new Translation(translations); diff --git a/assets/layers/etymology/etymology.json b/assets/layers/etymology/etymology.json index d49b45670..df89f5f81 100644 --- a/assets/layers/etymology/etymology.json +++ b/assets/layers/etymology/etymology.json @@ -23,6 +23,10 @@ "en": "All objects which have an etymology known", "nl": "Alle lagen met een gelinkt etymology" }, + "calculatedTags": [ + "_same_name_ids=feat.closestn('*', 250, undefined, 2500)?.filter(f => f.feat.properties.name === feat.properties.name)?.map(f => f.feat.properties.id)??[]", + "_total_segments=JSON.parse(feat.properties._same_name_ids).length + 1 // Plus one for the feature itself" + ], "tagRenderings": [ { "id": "etymology-images-from-wikipedia", @@ -115,6 +119,18 @@ "nl": "{image_carousel(image:streetsign)}
{image_upload(image:streetsign, Voeg afbeelding van straatnaambordje toe)}" } }, + { + "id": "minimap", + "render": { + "*": "{minimap(18, id, _same_name_ids):height:10rem}" + } + }, + { + "id": "etymology_multi_apply", + "render": { + "en": "{multi_apply(_same_name_ids, name:etymology:wikidata;name:etymology, Auto-applying data on all segments with the same name, true)}" + } + }, "wikipedia" ], "icon": { diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json index cb8084ad6..d795c741b 100644 --- a/assets/tagRenderings/questions.json +++ b/assets/tagRenderings/questions.json @@ -198,28 +198,32 @@ "if": "dog=yes", "then": { "en": "Dogs are allowed", - "nl": "honden zijn toegelaten" + "nl": "honden zijn toegelaten", + "pt": "Os cães são permitidos" } }, { "if": "dog=no", "then": { "en": "Dogs are not allowed", - "nl": "honden zijn niet toegelaten" + "nl": "honden zijn niet toegelaten", + "pt": "Os cães não são permitidos" } }, { "if": "dog=leashed", "then": { "en": "Dogs are allowed, but they have to be leashed", - "nl": "honden zijn enkel aan de leiband welkom" + "nl": "honden zijn enkel aan de leiband welkom", + "pt": "Os cães são permitidos, mas têm de ser presos pela trela" } }, { "if": "dog=unleashed", "then": { "en": "Dogs are allowed and can run around freely", - "nl": "honden zijn welkom en mogen vrij rondlopen" + "nl": "honden zijn welkom en mogen vrij rondlopen", + "pt": "Os cães são permitidos e podem correr livremente" } } ] @@ -294,7 +298,8 @@ "en": "Cash is accepted here", "nl": "Cash geld wordt hier aanvaard", "pt": "Aceitam pagamento com dinheiro aqui", - "pt_BR": "Dinheiro é aceito aqui" + "pt_BR": "Dinheiro é aceito aqui", + "id": "Disini menerima pembayaran tunai" } }, { @@ -304,7 +309,8 @@ "en": "Payment cards are accepted here", "nl": "Betalen met bankkaarten kan hier", "pt": "Aceitam pagamento com cartões bancários aqui", - "pt_BR": "Cartões de pagamento são aceitos aqui" + "pt_BR": "Cartões de pagamento são aceitos aqui", + "id": "Disini menerima pembayaran dengan kartu" } } ] @@ -406,7 +412,8 @@ "fr": "Premier étage", "pl": "Znajduje się na pierwszym piętrze", "sv": "Ligger på första våningen", - "pt": "Está no primeiro andar" + "pt": "Está no primeiro andar", + "id": "Berlokasi di lantai pertama" } } ] diff --git a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json index 489c36ed7..ce9864c20 100644 --- a/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json +++ b/assets/themes/toerisme_vlaanderen/toerisme_vlaanderen.json @@ -14,7 +14,7 @@ "nl": "Een kaart om toeristisch relevante info op aan te duiden" }, "description": { - "nl": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken." + "nl": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken.

Met de steun van Toerisme Vlaanderen" }, "descriptionTail": { "nl": "Met de steun van Toerisme Vlaanderen" diff --git a/langs/en.json b/langs/en.json index 92b0acc67..46afffb99 100644 --- a/langs/en.json +++ b/langs/en.json @@ -36,6 +36,9 @@ "splitTitle": "Choose on the map where to split this road", "hasBeenSplit": "This way has been split" }, + "multi_apply": { + "autoApply": "When changing the attributes {attr_names}, these attributes will automatically be changed on {count} other objects too" + }, "delete": { "delete": "Delete", "cancel": "Cancel", diff --git a/langs/layers/en.json b/langs/layers/en.json index 86eac29b2..96624bc97 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -2504,6 +2504,9 @@ "description": "All objects which have an etymology known", "name": "Has etymolgy", "tagRenderings": { + "etymology_multi_apply": { + "render": "{multi_apply(_same_name_ids, name:etymology:wikidata;name:etymology, Auto-applying data on all segments with the same name, true)}" + }, "simple etymology": { "mappings": { "0": { diff --git a/langs/themes/en.json b/langs/themes/en.json index 142ffcdfa..d5976735d 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1236,6 +1236,57 @@ "shortDescription": "A map with playgrounds", "title": "Playgrounds" }, + "postboxes": { + "description": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :)
Spotted an error or is a post box missing? You can edit this map with a free OpenStreetMap account. ", + "layers": { + "0": { + "description": "The layer showing postboxes.", + "name": "Postboxes", + "presets": { + "0": { + "title": "postbox" + } + }, + "title": { + "render": "Postbox" + } + }, + "1": { + "description": "A layer showing post offices.", + "filter": { + "0": { + "options": { + "0": { + "question": "Currently open" + } + } + } + }, + "name": "Post offices", + "presets": { + "0": { + "title": "Post Office" + } + }, + "tagRenderings": { + "OH": { + "mappings": { + "0": { + "then": "24/7 opened (including holidays)" + } + }, + "question": "What are the opening hours for this post office?", + "render": "Opening Hours: {opening_hours_table()}" + } + }, + "title": { + "render": "Post Office" + } + } + }, + "shortDescription": "A map showing postboxes and post offices", + "title": "Postbox and Post Office Map" + }, "shops": { "description": "On this map, one can mark basic information about shops, add opening hours and phone numbers", "layers": { @@ -1367,56 +1418,5 @@ "description": "On this map, you'll find waste baskets near you. If a waste basket is missing on this map, you can add it yourself", "shortDescription": "A map with waste baskets", "title": "Waste Basket" - }, - "postboxes": { - "description": "On this map you can find and add data of post offices and post boxes. You can use this map to find where you can mail your next postcard! :)
Spotted an error or is a post box missing? You can edit this map with a free OpenStreetMap account. ", - "layers": { - "0": { - "description": "The layer showing postboxes.", - "name": "Postboxes", - "presets": { - "0": { - "title": "postbox" - } - }, - "title": { - "render": "Postbox" - } - }, - "1": { - "description": "A layer showing post offices.", - "filter": { - "0": { - "options": { - "0": { - "question": "Currently open" - } - } - } - }, - "name": "Post offices", - "presets": { - "0": { - "title": "Post Office" - } - }, - "tagRenderings": { - "OH": { - "mappings": { - "0": { - "then": "24/7 opened (including holidays)" - } - }, - "question": "What are the opening hours for this post office?", - "render": "Opening Hours: {opening_hours_table()}" - } - }, - "title": { - "render": "Post Office" - } - } - }, - "shortDescription": "A map showing postboxes and post offices", - "title": "Postbox and Post Office Map" } } \ No newline at end of file diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 42e1edc56..11bf88734 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -1021,9 +1021,9 @@ }, "toerisme_vlaanderen": { "description": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:
  • Eetgelegenheden
  • Cafés en bars
  • (Fiets)oplaadpunten
  • Fietspompen, fietserverhuur en fietswinkels
  • Uitkijktorens
  • ...
Zie je fouten op de kaart? Dan kan je zelf makkelijk aanpasingen maken, die zichtbaar zijn voor iedereen. Hiervoor dien je een gratis OpenStreetMap account voor te maken.

Met de steun van Toerisme Vlaanderen", + "descriptionTail": "Met de steun van Toerisme Vlaanderen", "shortDescription": "Een kaart om toeristisch relevante info op aan te duiden", - "title": "Toeristisch relevante info", - "descriptionTail": "Met de steun van Toerisme Vlaanderen" + "title": "Toeristisch relevante info" }, "toilets": { "description": "Een kaart met openbare toiletten",