Add multi-apply box/feature, use it in etymology-theme to apply tags onto all segments of the same street
This commit is contained in:
parent
d0dfe9f607
commit
d3550fefbe
22 changed files with 355 additions and 78 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
name | default | description
|
||||
------ | --------- | -------------
|
||||
image key/prefix | image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc...
|
||||
image key/prefix (multiple values allowed if comma-seperated) | image | The keys given to the images, e.g. if <span class='literal-code'>image</span> is given, the first picture URL will be added as <span class='literal-code'>image</span>, the second as <span class='literal-code'>image:0</span>, the third as <span class='literal-code'>image:1</span>, etc...
|
||||
|
||||
#### Example usage
|
||||
|
||||
|
@ -26,10 +26,11 @@ image key/prefix | image | The keys given to the images, e.g. if <span class='li
|
|||
name | default | description
|
||||
------ | --------- | -------------
|
||||
image-key | image | Image tag to add the URL to (or image-tag:0, image-tag:1 when multiple images are added)
|
||||
label | Add image | The text to show on the button
|
||||
|
||||
#### Example usage
|
||||
|
||||
`{image_upload(image)}`
|
||||
`{image_upload(image,Add image)}`
|
||||
### wikipedia
|
||||
|
||||
A box showing the corresponding wikipedia article - based on the wikidata tag
|
||||
|
@ -154,4 +155,19 @@ minzoom | 18 | How far the contributor must zoom in before being able to import
|
|||
|
||||
#### Example usage
|
||||
|
||||
`{import_button(,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,18)}` Generated from UI/SpecialVisualisations.ts
|
||||
`{import_button(,Import this data into OpenStreetMap,./assets/svg/addSmall.svg,18)}`
|
||||
### multi_apply
|
||||
|
||||
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
|
||||
|
||||
name | default | description
|
||||
------ | --------- | -------------
|
||||
feature_ids | undefined | A JSOn-serialized list of IDs of features to apply the tagging on
|
||||
keys | undefined | One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features.
|
||||
text | undefined | The text to show on the button
|
||||
autoapply | undefined | 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
|
||||
overwrite | undefined | 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 usage
|
||||
|
||||
{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)} Generated from UI/SpecialVisualisations.ts
|
|
@ -497,6 +497,15 @@
|
|||
"key": "description:0",
|
||||
"description": "Layer 'Natuurgebied' shows and asks freeform values for key 'description:0' (in the MapComplete.osm.be theme 'De Natuur in')"
|
||||
},
|
||||
{
|
||||
"key": "wikidata",
|
||||
"description": "Layer 'Natuurgebied' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'De Natuur in')"
|
||||
},
|
||||
{
|
||||
"key": "wikidata",
|
||||
"description": "Layer 'Natuurgebied' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'De Natuur in') Picking this answer will delete the key wikidata.",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"key": "service:bicycle:cleaning:charge",
|
||||
"description": "Layer 'Natuurgebied' shows and asks freeform values for key 'service:bicycle:cleaning:charge' (in the MapComplete.osm.be theme 'De Natuur in')"
|
||||
|
|
|
@ -105,6 +105,15 @@
|
|||
"key": "wheelchair",
|
||||
"description": "Layer 'Observation towers' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Observation towers')",
|
||||
"value": "no"
|
||||
},
|
||||
{
|
||||
"key": "wikidata",
|
||||
"description": "Layer 'Observation towers' shows and asks freeform values for key 'wikidata' (in the MapComplete.osm.be theme 'Observation towers')"
|
||||
},
|
||||
{
|
||||
"key": "wikidata",
|
||||
"description": "Layer 'Observation towers' shows wikidata= with a fixed text, namely 'No Wikipedia page has been linked yet' (in the MapComplete.osm.be theme 'Observation towers') Picking this answer will delete the key wikidata.",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -119,7 +119,7 @@ export class ExtraFunction {
|
|||
{
|
||||
name: "closest",
|
||||
doc: "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)",
|
||||
args: ["list of features"]
|
||||
args: ["list of features or a layer name or '*' to get all features"]
|
||||
},
|
||||
(params, feature) => {
|
||||
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) => {
|
||||
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,7 +27,6 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
if(entity === undefined){
|
||||
return []
|
||||
}
|
||||
console.log("Entity:", entity)
|
||||
|
||||
const allImages : Promise<ProvidedImage>[] = []
|
||||
// P18 is the claim 'depicted in this image'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
158
UI/Popup/MultiApply.ts
Normal file
158
UI/Popup/MultiApply.ts
Normal file
|
@ -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<string[]>,
|
||||
keysToApply: string[],
|
||||
text: string,
|
||||
autoapply: boolean,
|
||||
overwrite: boolean,
|
||||
tagsSource: UIEventSource<any>,
|
||||
state: {
|
||||
changes: Changes,
|
||||
allElements: ElementStorage,
|
||||
layoutToUse: LayoutConfig,
|
||||
osmConnection: OsmConnection
|
||||
}
|
||||
}
|
||||
|
||||
class MultiApplyExecutor {
|
||||
|
||||
private readonly originalValues = new Map<string, string>()
|
||||
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<string, MultiApplyExecutor>()
|
||||
|
||||
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<boolean> = p.state.osmConnection.isLoggedIn.map(loggedIn => {
|
||||
return loggedIn && p.featureIds.data.length > 0
|
||||
}, [p.featureIds])
|
||||
super(new Combine(elems), undefined, isShown);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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<string[]> = tagsSource.map(tags => JSON.parse(tags[featureIdsKey]))
|
||||
return new MultiApply(
|
||||
{
|
||||
featureIds,
|
||||
keysToApply,
|
||||
text,
|
||||
autoapply,
|
||||
overwrite,
|
||||
tagsSource,
|
||||
state
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
static HelpMessage: BaseUIElement = SpecialVisualizations.GenHelpMessage();
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -217,7 +217,7 @@ export class Translation extends BaseUIElement {
|
|||
|
||||
static fromMap(transl: Map<string, string>) {
|
||||
const translations = {}
|
||||
transl.forEach((value, key) => {
|
||||
transl?.forEach((value, key) => {
|
||||
translations[key] = value
|
||||
})
|
||||
return new Translation(translations);
|
||||
|
|
|
@ -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)}<br/>{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": {
|
||||
|
|
|
@ -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 <b>not</b> allowed",
|
||||
"nl": "honden zijn <b>niet</b> toegelaten"
|
||||
"nl": "honden zijn <b>niet</b> toegelaten",
|
||||
"pt": "Os cães <b>não</b> são permitidos"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "dog=leashed",
|
||||
"then": {
|
||||
"en": "Dogs are allowed, but they have to be leashed",
|
||||
"nl": "honden zijn <b>enkel aan de leiband</b> welkom"
|
||||
"nl": "honden zijn <b>enkel aan de leiband</b> 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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:<br/><ul><li>Eetgelegenheden</li><li>Cafés en bars</li><li>(Fiets)oplaadpunten</li><li>Fietspompen, fietserverhuur en fietswinkels</li><li>Uitkijktorens</li><li>...</li></ul> 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:<br/><ul><li>Eetgelegenheden</li><li>Cafés en bars</li><li>(Fiets)oplaadpunten</li><li>Fietspompen, fietserverhuur en fietswinkels</li><li>Uitkijktorens</li><li>...</li></ul> 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.<br/><br/>Met de steun van Toerisme Vlaanderen<img src='./assets/themes/toerisme_vlaanderen/logo.png' />"
|
||||
},
|
||||
"descriptionTail": {
|
||||
"nl": "Met de steun van Toerisme Vlaanderen<img style='height:5rem; width: auto;' src='./assets/themes/toerisme_vlaanderen/logo.png' />"
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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! :)<br/>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! :)<br/>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"
|
||||
}
|
||||
}
|
|
@ -1021,9 +1021,9 @@
|
|||
},
|
||||
"toerisme_vlaanderen": {
|
||||
"description": "Op deze kaart kan je info zien die relevant is voor toerisme, zoals:<br/><ul><li>Eetgelegenheden</li><li>Cafés en bars</li><li>(Fiets)oplaadpunten</li><li>Fietspompen, fietserverhuur en fietswinkels</li><li>Uitkijktorens</li><li>...</li></ul> 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.<br/><br/>Met de steun van Toerisme Vlaanderen<img src='./assets/themes/toerisme_vlaanderen/logo.png' />",
|
||||
"descriptionTail": "Met de steun van Toerisme Vlaanderen<img style='height:5rem; width: auto;' src='./assets/themes/toerisme_vlaanderen/logo.png' />",
|
||||
"shortDescription": "Een kaart om toeristisch relevante info op aan te duiden",
|
||||
"title": "Toeristisch relevante info",
|
||||
"descriptionTail": "Met de steun van Toerisme Vlaanderen<img style='height:5rem; width: auto;' src='./assets/themes/toerisme_vlaanderen/logo.png' />"
|
||||
"title": "Toeristisch relevante info"
|
||||
},
|
||||
"toilets": {
|
||||
"description": "Een kaart met openbare toiletten",
|
||||
|
|
Loading…
Reference in a new issue