diff --git a/assets/layers/diets/diets.json b/assets/layers/diets/diets.json
index 0bc3795600..cac1388a31 100644
--- a/assets/layers/diets/diets.json
+++ b/assets/layers/diets/diets.json
@@ -12,9 +12,16 @@
"hidden"
],
"render": {
- "en": "Dietary options",
- "cs": "Dietní možnosti",
- "nl": "Dieetopties"
+ "special": {
+ "type": "show_icons",
+ "labels": "diets_content",
+ "class": "inline-flex float-right"
+ },
+ "before": {
+ "en": "Dietary options",
+ "cs": "Dietní možnosti",
+ "nl": "Dieetopties"
+ }
}
},
{
diff --git a/assets/layers/historic_rolling_stock/historic_rolling_stock.json b/assets/layers/historic_rolling_stock/historic_rolling_stock.json
index ffeea6dfbc..21eb1633f3 100644
--- a/assets/layers/historic_rolling_stock/historic_rolling_stock.json
+++ b/assets/layers/historic_rolling_stock/historic_rolling_stock.json
@@ -131,7 +131,8 @@
},
"tags": [
"historic=locomotive"
- ]
+ ],
+ "snapToLayer": ["railway"]
},
{
"title": {
@@ -144,7 +145,9 @@
},
"tags": [
"historic=railway_car"
- ]
+ ],
+ "snapToLayer": ["railway"]
+
},
{
"title": {
@@ -157,7 +160,9 @@
},
"tags": [
"historic=minecart"
- ]
+ ],
+ "snapToLayer": ["railway"]
+
}
],
"tagRenderings": [
diff --git a/assets/layers/icons/icons.json b/assets/layers/icons/icons.json
index 54ebd45d54..93e9e91ec0 100644
--- a/assets/layers/icons/icons.json
+++ b/assets/layers/icons/icons.json
@@ -430,10 +430,10 @@
}
},
{
- "id": "favourite_icon",
+ "condition": "_favourite=yes",
"description": "Only for rendering",
"icon": "circle:white;heart:red",
- "condition": "_favourite=yes",
+ "id": "favourite_icon",
"metacondition": "__showTimeSensitiveIcons!=no"
},
{
diff --git a/assets/layers/last_click/last_click.json b/assets/layers/last_click/last_click.json
index 3185c513fb..6aaa191159 100644
--- a/assets/layers/last_click/last_click.json
+++ b/assets/layers/last_click/last_click.json
@@ -217,8 +217,8 @@
},
{
"id": "debug",
- "render": "{all_tags()}",
- "metacondition": "__featureSwitchIsDebugging=true"
+ "metacondition": "__featureSwitchIsDebugging=true",
+ "render": "{all_tags()}"
}
],
"filter": [
diff --git a/assets/layers/note/note.json b/assets/layers/note/note.json
index b1dd36f327..eedef08c68 100644
--- a/assets/layers/note/note.json
+++ b/assets/layers/note/note.json
@@ -114,9 +114,9 @@
"lineRendering": [],
"tagRenderings": [
{
+ "classes": "p-0",
"id": "conversation",
- "render": "{visualize_note_comments()}",
- "classes": "p-0"
+ "render": "{visualize_note_comments()}"
},
{
"id": "add_image",
diff --git a/assets/layers/osm_community_index/osm_community_index.json b/assets/layers/osm_community_index/osm_community_index.json
index 1c605ca388..150fc6ecd9 100644
--- a/assets/layers/osm_community_index/osm_community_index.json
+++ b/assets/layers/osm_community_index/osm_community_index.json
@@ -66,16 +66,16 @@
],
"tagRenderings": [
{
- "id": "country_name",
+ "condition": "level=country",
"description": "The name of the country",
- "render": "{nameEn} {emojiFlag}",
- "condition": "level=country"
+ "id": "country_name",
+ "render": "{nameEn} {emojiFlag}"
},
{
- "id": "community_links",
+ "condition": "_community_links~*",
"description": "Community Links (Discord, meetups, Slack groups, IRC channels, mailing lists etc...)",
- "render": "{_community_links}",
- "condition": "_community_links~*"
+ "id": "community_links",
+ "render": "{_community_links}"
}
],
"filter": [
diff --git a/assets/layers/railway/railway.json b/assets/layers/railway/railway.json
new file mode 100644
index 0000000000..50ddecf0ba
--- /dev/null
+++ b/assets/layers/railway/railway.json
@@ -0,0 +1,66 @@
+{
+ "id": "railway",
+ "name": {
+ "en": "Railway"
+ },
+ "description": {
+ "en": "Railways and disused railways"
+ },
+ "source": {
+ "osmTags": {
+ "or": [
+ "railway=rail",
+ "railway=tram",
+ "railway=subway",
+ "railway=light_rail",
+
+ "railway=disused",
+
+ "disused:railway=rail",
+ "disused:railway=tram",
+ "disused:railway=subway",
+ "disused:railway=light_rail",
+
+ "abandoned:railway=rail",
+ "abandoned:railway=tram",
+ "abandoned:railway=subway",
+ "abandoned:railway=light_rail"
+ ]
+ }
+ },
+ "minzoom": 14,
+ "title": {
+ "render": {
+ "en": "Railway"
+ },
+ "icon": "./assets/svg/train.svg"
+ },
+ "pointRendering": [
+ {
+ "location": [
+ "point"
+ ],
+ "marker": [
+ {
+ "icon": "circle"
+ }
+ ]
+ }
+ ],
+ "lineRendering": [
+ {
+ "width": 1,
+ "color": "black"
+ }
+ ],
+ "tagRenderings": [
+ "images"
+ ],
+ "allowMove": false,
+ "#": "In first instance to snap historic rolling stock",
+ "snapName": {
+ "en": "railway track"
+ },
+ "credits": "mnalis ALTernative",
+ "credits:uid": 172435
+}
diff --git a/assets/themes/grb/grb.json b/assets/themes/grb/grb.json
index 337a137231..256070bca7 100644
--- a/assets/themes/grb/grb.json
+++ b/assets/themes/grb/grb.json
@@ -43,11 +43,24 @@
"id~relation/.*"
]
},
- "building~*"
+ {
+ "or": [
+ "building~*",
+ "building:part~*"
+ ]
+ }
]
}
},
- "title": "OSM-gebouw",
+ "title": {
+ "render": "OSM-building",
+ "mappings": [{
+ "if": "building:part~*",
+ "then": {
+ "en": "Building part"
+ }
+ }]
+ },
"tagRenderings": [
{
"id": "building type",
@@ -106,10 +119,12 @@
"if": "building=yes",
"then": "A building - no specification"
}
- ]
+ ],
+ "condition": "building:part="
},
{
"id": "grb-housenumber",
+ "condition": "building:part=",
"render": {
"nl": "Het huisnummer is {addr:housenumber}"
},
@@ -134,6 +149,7 @@
]
},
{
+ "condition": "building:part=",
"id": "grb-unit",
"question": "Wat is de wooneenheid-aanduiding?",
"render": {
@@ -150,6 +166,7 @@
]
},
{
+ "condition": "building:part=",
"id": "grb-street",
"render": {
"nl": "De straat is {addr:street}"
@@ -242,7 +259,49 @@
]
}
],
- "pointRendering": null,
+ "pointRendering": [
+ {
+ "marker": [{
+ "icon": "circle",
+ "color": {
+ "render": "#00c",
+ "mappings": [
+ {
+ "if": "fixme~*",
+ "then": "#ff00ff"
+ },
+ {
+ "if": "building=house",
+ "then": "#a00"
+ },
+ {
+ "if": "building=shed",
+ "then": "#563e02"
+ },
+ {
+ "if": {
+ "or": [
+ "building=garage",
+ "building=garages"
+ ]
+ },
+ "then": "#f9bfbb"
+ },
+ {
+ "if": "building=yes",
+ "then": "#0774f2"
+ },
+ {
+ "if": "building:part~*",
+ "then": "#f8fc25"
+ }
+ ]
+ }
+ }],
+ "location": ["centroid"],
+ "iconSize": "10,10"
+ }
+ ],
"lineRendering": [
{
"width": {
@@ -281,6 +340,10 @@
{
"if": "building=yes",
"then": "#0774f2"
+ },
+ {
+ "if": "building:part~*",
+ "then": "#f8fc25"
}
]
}
diff --git a/assets/themes/historic_rolling_stock/historic_rolling_stock.json b/assets/themes/historic_rolling_stock/historic_rolling_stock.json
index 0b22c6b2b9..077324f278 100644
--- a/assets/themes/historic_rolling_stock/historic_rolling_stock.json
+++ b/assets/themes/historic_rolling_stock/historic_rolling_stock.json
@@ -18,6 +18,14 @@
},
"icon": "./assets/layers/historic_rolling_stock/steam_locomotive.svg",
"layers": [
- "historic_rolling_stock"
+ "historic_rolling_stock",
+ {
+ "builtin": "railway",
+ "override": {
+ "name": null,
+ "presets": null,
+ "shownByDefault": false
+ }
+ }
]
}
diff --git a/assets/themes/nature/nature.json b/assets/themes/nature/nature.json
index 08571b3f80..7158a1d5e6 100644
--- a/assets/themes/nature/nature.json
+++ b/assets/themes/nature/nature.json
@@ -58,6 +58,14 @@
"drinking_water",
"birdhide",
"nature_reserve",
+ {
+ "builtin": [
+ "shelter"
+ ],
+ "override": {
+ "minzoom": 11
+ }
+ },
{
"builtin": [
"map",
@@ -66,7 +74,6 @@
"picnic_table",
"toilet",
"guidepost",
- "shelter",
"bbq",
"firepit",
"insect_hotel",
diff --git a/assets/themes/pets/pets.json b/assets/themes/pets/pets.json
index 8740095fe2..d93ab452f0 100644
--- a/assets/themes/pets/pets.json
+++ b/assets/themes/pets/pets.json
@@ -100,6 +100,48 @@
"name": null
}
},
+ {
+ "builtin": "cafe_pub",
+ "override": {
+ "id": "cafe_pub_dog_friendly",
+ "name": {
+ "en": "Dog friendly drinking places",
+ "da": "Hundevenlige værtshuse"
+ },
+ "pointRendering": [
+ {
+ "iconBadges+": [
+ "icons.dogicon"
+ ]
+ }
+ ],
+ "=presets": [],
+ "source": {
+ "osmTags": {
+ "and+": [
+ {
+ "or": [
+ "dog=unleashed",
+ "dog=leashed",
+ "dog=yes"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "builtin": "cafe_pub",
+ "override": {
+ "minzoom": 18,
+ "isCounted": false,
+ "filter": {
+ "sameAs": "cafe_pub_dog_friendly"
+ },
+ "name": null
+ }
+ },
{
"builtin": "shops",
"override": {
@@ -227,4 +269,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/langs/layers/cs.json b/langs/layers/cs.json
index 067e08c2a8..2b661de30c 100644
--- a/langs/layers/cs.json
+++ b/langs/layers/cs.json
@@ -4751,7 +4751,9 @@
"diets": {
"tagRenderings": {
"diets_title": {
- "render": "Dietní možnosti"
+ "render": {
+ "before": "Dietní možnosti"
+ }
},
"gluten_free": {
"mappings": {
diff --git a/langs/layers/en.json b/langs/layers/en.json
index f6476e968c..6365bf5d67 100644
--- a/langs/layers/en.json
+++ b/langs/layers/en.json
@@ -4768,7 +4768,9 @@
"diets": {
"tagRenderings": {
"diets_title": {
- "render": "Dietary options"
+ "render": {
+ "before": "Dietary options"
+ }
},
"gluten_free": {
"mappings": {
@@ -10092,6 +10094,14 @@
}
}
},
+ "railway": {
+ "description": "Railways and disused railways",
+ "name": "Railway",
+ "snapName": "railway track",
+ "title": {
+ "render": "Railway"
+ }
+ },
"railway_platforms": {
"description": "Find every platform in the station, and the train routes that use them.",
"name": "Railway Platforms",
diff --git a/langs/layers/nl.json b/langs/layers/nl.json
index 03ff99a8e4..6e47acc32c 100644
--- a/langs/layers/nl.json
+++ b/langs/layers/nl.json
@@ -4561,7 +4561,9 @@
"diets": {
"tagRenderings": {
"diets_title": {
- "render": "Dieetopties"
+ "render": {
+ "before": "Dieetopties"
+ }
},
"gluten_free": {
"mappings": {
diff --git a/langs/themes/en.json b/langs/themes/en.json
index a23dea4728..c2dd87052c 100644
--- a/langs/themes/en.json
+++ b/langs/themes/en.json
@@ -646,6 +646,13 @@
"grb-reference": {
"render": "Has been imported from GRB, reference number is {source:geometry:ref}"
}
+ },
+ "title": {
+ "mappings": {
+ "0": {
+ "then": "Building part"
+ }
+ }
}
},
"1": {
diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts
index ffd9e78cca..6414ed5f6c 100644
--- a/scripts/generateLayerOverview.ts
+++ b/scripts/generateLayerOverview.ts
@@ -37,15 +37,8 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
-import {
- LayerConfigDependencyGraph,
- LevelInfo,
-} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
import { Lists } from "../src/Utils/Lists"
-import {
- LayerConfigDependencyGraph,
- LevelInfo,
-} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
+import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
import { AddContextToTranslations } from "../src/Models/ThemeConfig/Conversion/AddContextToTranslations"
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
@@ -121,7 +114,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
static singleton = new AddIconSummary()
constructor() {
- super("AddIconSummary", "Adds an icon summary for quick reference")
+ super("AddIconSummary", "Adds an icon summary ('_layerIcon') for quick reference. This previews how the layer should be shown in e.g. the filter menu")
}
convert(json: { raw: LayerConfigJson; parsed: LayerConfig }) {
@@ -706,8 +699,8 @@ class LayerOverviewUtils extends Script {
)
const path = "assets/layers/questions/questions.json"
- const sharedQuestionsRaw = this.parseLayer(doesImageExist, prepareLayer, path).raw
- const sharedQuestions = new AddContextToTranslations("").convertStrict(
+ const sharedQuestionsRaw: LayerConfigJson = this.parseLayer(doesImageExist, prepareLayer, path).raw
+ const sharedQuestions: LayerConfigJson = new AddContextToTranslations("").convertStrict(
sharedQuestionsRaw,
ConversionContext.construct(["layers:questions"], [])
)
diff --git a/src/Models/MenuState.ts b/src/Models/MenuState.ts
index 627d1e2669..98ec28ba86 100644
--- a/src/Models/MenuState.ts
+++ b/src/Models/MenuState.ts
@@ -90,6 +90,18 @@ export class MenuState {
if (!visitedBefore.data && shouldShowWelcomeMessage) {
this.pageStates.about_theme.set(true)
visitedBefore.set(true)
+ this._selectedElement.addCallbackD(() => {
+ if(this.pageStates.about_theme.data){
+ this.pageStates.about_theme.set(false)
+ this._selectedElement.addCallbackAndRun(selected => {
+ if(!selected){
+ this.pageStates.about_theme.set(true)
+ return true
+ }
+ })
+ return true
+ }
+ })
}
}
diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
index a541856b8b..1602f7a5a5 100644
--- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts
+++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts
@@ -299,7 +299,7 @@ export interface LayerConfigJson {
/**
* Advanced option - might be set by the theme compiler
*
- * If true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden.
+ * If true, this data will _always_ be loaded, even if the layer is disabled by a filter or hidden.
* The opposite of `doNotDownload`
*
* question: Should this layer be forcibly loaded?
diff --git a/src/Models/ThemeConfig/TagRenderingConfig.ts b/src/Models/ThemeConfig/TagRenderingConfig.ts
index 5f915cd424..da027a3499 100644
--- a/src/Models/ThemeConfig/TagRenderingConfig.ts
+++ b/src/Models/ThemeConfig/TagRenderingConfig.ts
@@ -523,7 +523,9 @@ export default class TagRenderingConfig {
/**
* Gets all the render values. Will return multiple render values if 'multianswer' is enabled.
- * The result will equal [GetRenderValue] if not 'multiAnswer'
+ * The result will equal [GetRenderValue] if not 'multiAnswer'.
+ *
+ * If an iconsource is given, will return an icon too (but not necessarly an iconSize)
* @param tags
* @constructor
*/
diff --git a/src/Models/ThemeViewState/WithChangesState.ts b/src/Models/ThemeViewState/WithChangesState.ts
index a7f919648c..27c2b85f1e 100644
--- a/src/Models/ThemeViewState/WithChangesState.ts
+++ b/src/Models/ThemeViewState/WithChangesState.ts
@@ -21,6 +21,7 @@ import SelectedElementTagsUpdater from "../../Logic/Actors/SelectedElementTagsUp
import NoElementsInViewDetector, {
FeatureViewState,
} from "../../Logic/Actors/NoElementsInViewDetector"
+import { features } from "monaco-editor/esm/metadata"
export class WithChangesState extends WithLayoutSourceState {
readonly changes: Changes
@@ -226,15 +227,10 @@ export class WithChangesState extends WithLayoutSourceState {
metaTags: this.userRelatedState.preferencesAsTags,
selectedElement: this.selectedElement,
fetchStore: (id) => this.featureProperties.getStore(id),
+ onClick: feature => {
+ this.setSelectedElement(feature)
+ }
})
- /*new ShowDataLayer(map, {
- layer: fs.layer.layerDef,
- features: filtered,
- doShowLayer,
- metaTags: this.userRelatedState.preferencesAsTags,
- selectedElement: this.selectedElement,
- fetchStore: (id) => this.featureProperties.getStore(id),
- })*/
})
return filteringFeatureSource
}
diff --git a/src/Models/ThemeViewState/WithLayoutSourceState.ts b/src/Models/ThemeViewState/WithLayoutSourceState.ts
index cb9ceeeac2..d09f41d965 100644
--- a/src/Models/ThemeViewState/WithLayoutSourceState.ts
+++ b/src/Models/ThemeViewState/WithLayoutSourceState.ts
@@ -130,7 +130,8 @@ export class WithLayoutSourceState extends WithSelectedElementState {
}
protected setSelectedElement(feature: Feature) {
- // The given feature might be a partial one from the cache
+ // The given feature might be a partial one from the cache or might be a centroid point instead of the way
+ // We lookup a version by IDP
if (feature !== undefined) {
feature =
this.indexedFeatures.featuresById.data?.get(feature?.properties?.id) ?? feature
diff --git a/src/Models/ThemeViewState/WithSpecialLayers.ts b/src/Models/ThemeViewState/WithSpecialLayers.ts
index 15cdc4cb62..ff2bb58df5 100644
--- a/src/Models/ThemeViewState/WithSpecialLayers.ts
+++ b/src/Models/ThemeViewState/WithSpecialLayers.ts
@@ -4,7 +4,7 @@ import FavouritesFeatureSource from "../../Logic/FeatureSource/Sources/Favourite
import Constants from "../Constants"
import { FeatureSource } from "../../Logic/FeatureSource/FeatureSource"
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
-import { Feature } from "geojson"
+import { Feature, Geometry } from "geojson"
import { BBox } from "../../Logic/BBox"
import ShowDataLayer from "../../UI/Map/ShowDataLayer"
import MetaTagging from "../../Logic/MetaTagging"
@@ -22,6 +22,7 @@ import {
} from "../../Logic/FeatureSource/TiledFeatureSource/SummaryTileSource"
import { ShowDataLayerOptions } from "../../UI/Map/ShowDataLayerOptions"
import { ClusterGrouping } from "../../Logic/FeatureSource/TiledFeatureSource/ClusteringFeatureSource"
+import { OsmTags } from "../OsmFeature"
export class WithSpecialLayers extends WithChangesState {
readonly favourites: FavouritesFeatureSource
@@ -180,7 +181,7 @@ export class WithSpecialLayers extends WithChangesState {
})
)
// show last click = new point/note marker
- const features = new StaticFeatureSource(lastClickFiltered)
+ const features: StaticFeatureSource & {id: string}>> = new StaticFeatureSource(lastClickFiltered)
this.featureProperties.trackFeatureSource(features)
new ShowDataLayer(this.map, {
features,
diff --git a/src/UI/Map/ShowDataLayer.ts b/src/UI/Map/ShowDataLayer.ts
index 4d80c6c926..434e705fd7 100644
--- a/src/UI/Map/ShowDataLayer.ts
+++ b/src/UI/Map/ShowDataLayer.ts
@@ -459,11 +459,6 @@ export default class ShowDataLayer {
preprocessPoints,
} = this._options
let onClick = this._options.onClick
- if (!onClick && selectedElement && layer.title !== undefined) {
- onClick = (feature: Feature) => {
- selectedElement?.setData(feature)
- }
- }
if (drawLines !== false) {
for (let i = 0; i < layer.lineRendering.length; i++) {
const lineRenderingConfig = layer.lineRendering[i]
diff --git a/src/UI/Popup/AutoApplyButtonVis.ts b/src/UI/Popup/AutoApplyButtonVis.ts
index 9bfa3c3659..8257745e82 100644
--- a/src/UI/Popup/AutoApplyButtonVis.ts
+++ b/src/UI/Popup/AutoApplyButtonVis.ts
@@ -2,8 +2,9 @@ import { Store, Stores, UIEventSource } from "../../Logic/UIEventSource"
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
import { Changes } from "../../Logic/Osm/Changes"
import {
+ SpecialVisualisationArg,
+ SpecialVisualisationParams,
SpecialVisualization,
- SpecialVisualizationState,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import { IndexedFeatureSource } from "../../Logic/FeatureSource/FeatureSource"
@@ -31,12 +32,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte {
public readonly funcName: string = "auto_apply"
public readonly needsUrls = []
public readonly group = "data_import"
- public readonly args: {
- name: string
- defaultValue?: string
- doc: string
- required?: boolean
- }[] = [
+ public readonly args: SpecialVisualisationArg[] = [
{
name: "target_layer",
doc: "The layer that the target features will reside in",
@@ -54,6 +50,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte {
},
{
name: "text",
+ type:"translation",
doc: "The text to show on the button",
required: true,
},
@@ -86,15 +83,11 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte {
4. At last, add this component`
}
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- argument: string[]
- ): SvelteUIElement {
- const target_layer_id = argument[0]
- const targetTagRendering = argument[2]
- const text = argument[3]
- const icon = argument[4]
+ constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement {
+ const target_layer_id = args[0]
+ const targetTagRendering = args[2]
+ const text = args[3]
+ const icon = args[4]
const options = {
target_layer_id,
targetTagRendering,
@@ -105,7 +98,7 @@ export default class AutoApplyButtonVis extends SpecialVisualizationSvelte {
const to_parse: UIEventSource = new UIEventSource(undefined)
Stores.chronic(500, () => to_parse.data === undefined)
.map(() => {
- const applicable = tagSource.data[argument[1]]
+ const applicable = tags.data[args[1]]
if (typeof applicable === "string") {
return JSON.parse(applicable)
} else {
diff --git a/src/UI/Popup/DataExportVisualisations.ts b/src/UI/Popup/DataExportVisualisations.ts
index 81f5f3747f..dc82a9125e 100644
--- a/src/UI/Popup/DataExportVisualisations.ts
+++ b/src/UI/Popup/DataExportVisualisations.ts
@@ -1,11 +1,5 @@
-import {
- SpecialVisualization,
- SpecialVisualizationState,
- SpecialVisualizationSvelte,
-} from "../SpecialVisualization"
-import { UIEventSource } from "../../Logic/UIEventSource"
+import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationSvelte } from "../SpecialVisualization"
import { Feature, LineString } from "geojson"
-import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import Translations from "../i18n/Translations"
import SvelteUIElement from "../Base/SvelteUIElement"
import ExportFeatureButton from "./ExportFeatureButton.svelte"
@@ -17,13 +11,7 @@ class ExportAsGpxVis extends SpecialVisualizationSvelte {
args = []
needsUrls = []
- constr(
- state: SpecialVisualizationState,
- tags: UIEventSource>,
- argument: string[],
- feature: Feature,
- layer: LayerConfig
- ) {
+ constr({ tags, feature, layer }: SpecialVisualisationParams) {
if (feature.geometry.type !== "LineString") {
return undefined
}
@@ -48,7 +36,7 @@ class ExportAsGeojsonVis extends SpecialVisualizationSvelte {
docs = "Exports the selected feature as GeoJson-file"
args = []
- constr(state, tags, args, feature, layer) {
+ constr({ tags, feature, layer }: SpecialVisualisationParams) {
const t = Translations.t.general.download
return new SvelteUIElement(ExportFeatureButton, {
tags,
@@ -64,7 +52,7 @@ class ExportAsGeojsonVis extends SpecialVisualizationSvelte {
}
export class DataExportVisualisations {
- public static initList(): SpecialVisualization[] {
+ public static initList(): SpecialVisualizationSvelte[] {
return [new ExportAsGpxVis(), new ExportAsGeojsonVis()]
}
}
diff --git a/src/UI/Popup/DataVisualisations.ts b/src/UI/Popup/DataVisualisations.ts
index 5a721e162f..97fd3c10d3 100644
--- a/src/UI/Popup/DataVisualisations.ts
+++ b/src/UI/Popup/DataVisualisations.ts
@@ -1,11 +1,11 @@
import {
+ SpecialVisualisationArg,
+ SpecialVisualisationParams,
SpecialVisualization,
- SpecialVisualizationState,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import { HistogramViz } from "./HistogramViz"
-import { Store, UIEventSource } from "../../Logic/UIEventSource"
-import { Feature } from "geojson"
+import { Store } from "../../Logic/UIEventSource"
import BaseUIElement from "../BaseUIElement"
import SvelteUIElement from "../Base/SvelteUIElement"
import DirectionIndicator from "../Base/DirectionIndicator.svelte"
@@ -20,15 +20,18 @@ import NextChangeViz from "../OpeningHours/NextChangeViz.svelte"
import { Unit } from "../../Models/Unit"
import AllFeaturesStatistics from "../Statistics/AllFeaturesStatistics.svelte"
import { LanguageElement } from "./LanguageElement/LanguageElement"
-import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import { QuestionableTagRenderingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import { And } from "../../Logic/Tags/And"
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
import TagRenderingEditable from "./TagRendering/TagRenderingEditable.svelte"
import AllTagsPanel from "./AllTagsPanel/AllTagsPanel.svelte"
import CollectionTimes from "../CollectionTimes/CollectionTimes.svelte"
+import Tr from "../Base/Tr.svelte"
+import Combine from "../Base/Combine"
+import Marker from "../Map/Marker.svelte"
+import { twJoin } from "tailwind-merge"
-class DirectionIndicatorVis extends SpecialVisualization {
+class DirectionIndicatorVis extends SpecialVisualizationSvelte {
funcName = "direction_indicator"
args = []
@@ -36,13 +39,8 @@ class DirectionIndicatorVis extends SpecialVisualization {
"Gives a distance indicator and a compass pointing towards the location from your GPS-location. If clicked, centers the map on the object"
group = "data"
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- argument: string[],
- feature: Feature
- ): BaseUIElement {
- return new SvelteUIElement(DirectionIndicator, { state, feature })
+ constr(params: SpecialVisualisationParams): SvelteUIElement {
+ return new SvelteUIElement(DirectionIndicator, params)
}
}
@@ -65,17 +63,15 @@ class DirectionAbsolute extends SpecialVisualization {
]
group = "data"
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- args: string[]
- ): BaseUIElement {
+ constr({
+ tags,
+ args,
+ }: SpecialVisualisationParams): BaseUIElement {
const key = args[0] === "" ? "_direction:centerpoint" : args[0]
const offset = args[1] === "" ? 0 : Number(args[1])
return new VariableUiElement(
- tagSource
- .map((tags) => {
+ tags.map((tags) => {
console.log("Direction value", tags[key], key)
return tags[key]
})
@@ -117,14 +113,12 @@ class OpeningHoursTableVis extends SpecialVisualizationSvelte {
example =
"A normal opening hours table can be invoked with `{opening_hours_table()}`. A table for e.g. conditional access with opening hours can be `{opening_hours_table(access:conditional, no @ &LPARENS, &RPARENS)}`"
- constr(state, tagSource: UIEventSource, args) {
+ constr({ tags, args }: SpecialVisualisationParams): SvelteUIElement {
const [key, prefix, postfix] = args
const openingHoursStore: Store =
- OH.CreateOhObjectStore(tagSource, key, prefix, postfix)
+ OH.CreateOhObjectStore(tags, key, prefix, postfix)
return new SvelteUIElement(OpeningHoursWithError, {
- tags: tagSource,
- key,
- opening_hours_obj: openingHoursStore,
+ tags, key, opening_hours_obj: openingHoursStore,
})
}
}
@@ -152,11 +146,7 @@ class OpeningHoursState extends SpecialVisualizationSvelte {
},
]
- constr(
- state: SpecialVisualizationState,
- tags: UIEventSource>,
- args: string[]
- ): SvelteUIElement {
+ constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement {
const keyToUse = args[0]
const prefix = args[1]
const postfix = args[2]
@@ -187,10 +177,10 @@ class Canonical extends SpecialVisualization {
},
]
- constr(state, tagSource, args) {
+ constr({ state, tags, args }: SpecialVisualisationParams) {
const key = args[0]
return new VariableUiElement(
- tagSource
+ tags
.map((tags) => tags[key])
.map((value) => {
if (value === undefined) {
@@ -203,7 +193,7 @@ class Canonical extends SpecialVisualization {
if (unit === undefined) {
return value
}
- const getCountry = () => tagSource.data._country
+ const getCountry = () => tags.data._country
return unit.asHumanLongValue(value, getCountry)
})
)
@@ -217,26 +207,24 @@ class StatisticsVis extends SpecialVisualizationSvelte {
"Show general statistics about all the elements currently in view. Intended to use on the `current_view`-layer. They will be split per layer"
args = []
- constr(state) {
- return new SvelteUIElement(AllFeaturesStatistics, { state })
+ constr(params: SpecialVisualisationParams) {
+ return new SvelteUIElement(AllFeaturesStatistics, params)
}
}
-class PresetDescription extends SpecialVisualization {
+class PresetDescription extends SpecialVisualizationSvelte {
funcName = "preset_description"
docs =
"Shows the extra description from the presets of the layer, if one matches. It will pick the most specific one (e.g. if preset `A` implies `B`, but `B` does not imply `A`, it'll pick B) or the first one if no ordering can be made. Might be empty"
args = []
+ group = "UI"
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>
- ): BaseUIElement {
- const translation = tagSource.map((tags) => {
+ constr({ state, tags }: SpecialVisualisationParams): SvelteUIElement {
+ const translation = tags.map((tags) => {
const layer = state.theme.getMatchingLayer(tags)
return layer?.getMostMatchingPreset(tags)?.description
})
- return new VariableUiElement(translation)
+ return new SvelteUIElement(Tr, { t: translation })
}
}
@@ -244,14 +232,9 @@ class PresetTypeSelect extends SpecialVisualizationSvelte {
funcName = "preset_type_select"
docs = "An editable tag rendering which allows to change the type"
args = []
+ group = "ui"
- constr(
- state: SpecialVisualizationState,
- tags: UIEventSource>,
- argument: string[],
- selectedElement: Feature,
- layer: LayerConfig
- ): SvelteUIElement {
+ constr({ state, tags, feature, layer }: SpecialVisualisationParams,): SvelteUIElement {
const t = Translations.t.preset_type
if (layer._basedOn !== layer.id) {
console.warn("Trying to use the _original_ layer")
@@ -277,7 +260,7 @@ class PresetTypeSelect extends SpecialVisualizationSvelte {
return new SvelteUIElement(TagRenderingEditable, {
config,
tags,
- selectedElement,
+ selectedElement: feature,
state,
layer,
})
@@ -290,8 +273,8 @@ class AllTagsVis extends SpecialVisualizationSvelte {
args = []
group = "data"
- constr(state, tags: UIEventSource>, _, __, layer: LayerConfig) {
- return new SvelteUIElement(AllTagsPanel, { tags, layer })
+ constr(params: SpecialVisualisationParams) {
+ return new SvelteUIElement(AllTagsPanel, params)
}
}
@@ -302,23 +285,18 @@ class PointsInTimeVis extends SpecialVisualization {
args = [
{
name: "key",
+ type:"key",
required: true,
doc: "The key out of which the points_in_time will be parsed",
},
]
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- args: string[],
- feature: Feature,
- layer: LayerConfig
- ): BaseUIElement {
+ constr({ tags, args }: SpecialVisualisationParams): BaseUIElement {
const key = args[0]
- const points_in_time = tagSource.map((tags) => tags[key])
+ const points_in_time = tags.map((tags) => tags[key])
const times = points_in_time.map(
- (times) => OH.createOhObject(tagSource.data, times, tagSource.data["_country"], 1),
- [tagSource]
+ (times) => OH.createOhObject(tags.data, times, tags.data["_country"], 1),
+ [tags]
)
return new VariableUiElement(
times.map((times) => new SvelteUIElement(CollectionTimes, { times }))
@@ -326,6 +304,60 @@ class PointsInTimeVis extends SpecialVisualization {
}
}
+class KnownIcons extends SpecialVisualization {
+ docs = "Displays all icons from the specified tagRenderings (if they are known and have an icon) together, e.g. to give a summary of the dietary options"
+ needsUrls = []
+ group = "UI"
+ funcName = "show_icons"
+ args: SpecialVisualisationArg[] = [{
+ name: "labels",
+ doc: "A ';'-separated list of labels and/or ids of tagRenderings",
+ type: "key",
+ required: true,
+ }, {
+ name: "class",
+ doc: "CSS-classes of the container, space-separated",
+ type: "css",
+ required: false,
+ defaultValue: "inline-flex mx-4",
+ }]
+
+ private static readonly emojiHeights = {
+ small: "2rem",
+ medium: "3rem",
+ large: "5rem",
+ }
+
+ constr(options: SpecialVisualisationParams): BaseUIElement {
+ const labels = new Set(options.args[0].split(";").map(s => s.trim()))
+ const matchingTrs = options.layer.tagRenderings.filter(
+ tr => labels.has(tr.id) || tr.labels.some(l => labels.has(l)),
+ )
+ return new VariableUiElement(options.tags.map(tags =>
+ new Combine(matchingTrs.map(tr => {
+ const mapping = tr.GetRenderValueWithImage(tags)
+ if (!mapping?.icon) {
+ return undefined
+ }
+
+ return new SvelteUIElement(Marker, {
+ emojiHeight: KnownIcons.emojiHeights[mapping.iconClass] ?? "2rem",
+ clss: `mapping-icon-${mapping.iconClass ?? "small"}`,
+ icons: mapping.icon,
+ size: twJoin(
+ "shrink-0",
+ `mapping-icon-${mapping.iconClass ?? "small"}-height mapping-icon-${
+ mapping.iconClass ?? "small"
+ }-width`),
+
+
+ })
+ })
+ ).SetClass(options.args[1] ?? "inline-flex mx-4")
+ ))
+ }
+}
+
export class DataVisualisations {
public static initList(): SpecialVisualization[] {
return [
@@ -341,6 +373,7 @@ export class DataVisualisations {
new PresetDescription(),
new PresetTypeSelect(),
new AllTagsVis(),
+ new KnownIcons(),
]
}
}
diff --git a/src/UI/Popup/HistogramViz.ts b/src/UI/Popup/HistogramViz.ts
index 679255d652..7cfffd1f4b 100644
--- a/src/UI/Popup/HistogramViz.ts
+++ b/src/UI/Popup/HistogramViz.ts
@@ -1,5 +1,5 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource"
-import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
+import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
import { Feature } from "geojson"
import SvelteUIElement from "../Base/SvelteUIElement"
import Histogram from "../BigComponents/Histogram.svelte"
@@ -14,6 +14,7 @@ export class HistogramViz extends SpecialVisualization {
args = [
{
name: "key",
+ type:"key",
doc: "The key to be read and to generate a histogram from",
required: true,
},
@@ -35,12 +36,8 @@ export class HistogramViz extends SpecialVisualization {
]
}
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- args: string[]
- ) {
- const values: Store = tagSource.map((tags) => {
+ constr( {tags, args}: SpecialVisualisationParams): SvelteUIElement {
+ const values: Store = tags.map((tags) => {
const value = tags[args[0]]
try {
if (value === "" || value === undefined) {
diff --git a/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts b/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts
index f72497649a..fce251a7dc 100644
--- a/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts
+++ b/src/UI/Popup/ImportButtons/ConflateImportButtonViz.ts
@@ -1,7 +1,11 @@
-import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
+import {
+ SpecialVisualisationArg,
+ SpecialVisualisationParams,
+ SpecialVisualizationSvelte,
+ SpecialVisualizationUtils,
+} from "../../SpecialVisualization"
import { UIEventSource } from "../../../Logic/UIEventSource"
import { Feature, Geometry, LineString, Polygon } from "geojson"
-import BaseUIElement from "../../BaseUIElement"
import { ImportFlowArguments, ImportFlowUtils } from "./ImportFlow"
import Translations from "../../i18n/Translations"
import { Utils } from "../../../Utils"
@@ -14,6 +18,7 @@ import { Changes } from "../../../Logic/Osm/Changes"
import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
import { OsmConnection } from "../../../Logic/Osm/OsmConnection"
import { OsmTags } from "../../../Models/OsmFeature"
+import Tr from "../../Base/Tr.svelte"
export interface ConflateFlowArguments extends ImportFlowArguments {
way_to_conflate: string
@@ -22,21 +27,17 @@ export interface ConflateFlowArguments extends ImportFlowArguments {
snap_onto_layers?: string
}
-export default class ConflateImportButtonViz extends SpecialVisualization implements AutoAction {
+export default class ConflateImportButtonViz extends SpecialVisualizationSvelte implements AutoAction {
supportsAutoAction: boolean = true
needsUrls = []
group = "data_import"
public readonly funcName: string = "conflate_button"
- public readonly args: {
- name: string
- defaultValue?: string
- doc: string
- required?: boolean
- }[] = [
+ public readonly args: SpecialVisualisationArg[] = [
...ImportFlowUtils.generalArguments,
{
name: "way_to_conflate",
+ type:"key",
doc: "The key, of which the corresponding value is the id of the OSM-way that must be conflated; typically a calculatedTag",
},
]
@@ -84,32 +85,25 @@ export default class ConflateImportButtonViz extends SpecialVisualization implem
await state.changes.applyAction(action)
}
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource,
- argument: string[],
- feature: Feature
- ): BaseUIElement {
+ constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement {
const canBeImported =
feature.geometry.type === "LineString" ||
(feature.geometry.type === "Polygon" && feature.geometry.coordinates.length === 1)
if (!canBeImported) {
- return Translations.t.general.add.import.wrongTypeToConflate.SetClass("alert")
+ return new SvelteUIElement(Tr, { t: Translations.t.general.add.import.wrongTypeToConflate, cls: "alert" })
}
- const args: ConflateFlowArguments = Utils.ParseVisArgs(this.args, argument)
- const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, args)
- const idOfWayToReplaceGeometry = tagSource.data[args.way_to_conflate]
+ const argsParsed: ConflateFlowArguments = SpecialVisualizationUtils.parseArgs(this.args, args)
+ const tagsToApply = ImportFlowUtils.getTagsToApply(>tags, argsParsed)
+ const idOfWayToReplaceGeometry = tags.data[argsParsed.way_to_conflate]
const importFlow = new ConflateImportFlowState(
state,
>feature,
- args,
+ argsParsed,
tagsToApply,
- tagSource,
+ tags,
idOfWayToReplaceGeometry
)
- return new SvelteUIElement(WayImportFlow, {
- importFlow,
- })
+ return new SvelteUIElement(WayImportFlow, { importFlow })
}
getLayerDependencies = (args: string[]) =>
diff --git a/src/UI/Popup/ImportButtons/ImportFlow.ts b/src/UI/Popup/ImportButtons/ImportFlow.ts
index 3deea70ed5..4ad16da1e2 100644
--- a/src/UI/Popup/ImportButtons/ImportFlow.ts
+++ b/src/UI/Popup/ImportButtons/ImportFlow.ts
@@ -66,13 +66,14 @@ ${Utils.special_visualizations_importRequirementDocs}
* Given the tagsstore of the point which represents the challenge, creates a new store with tags that should be applied onto the newly created point,
*/
public static getTagsToApply(
- originalFeatureTags: UIEventSource,
+ originalFeatureTags: Store,
args: { tags: string }
): Store {
if (originalFeatureTags === undefined) {
return undefined
}
let newTags: Store
+ // Listing of the keys that should be transferred
const tags = args.tags
if (
tags.indexOf(" ") < 0 &&
@@ -81,12 +82,6 @@ ${Utils.special_visualizations_importRequirementDocs}
) {
// This is a property to expand...
const items: string = originalFeatureTags.data[tags]
- console.debug(
- "The import button is using tags from properties[" +
- tags +
- "] of this object, namely ",
- items
- )
if (items.startsWith("{")) {
// This is probably a JSON
diff --git a/src/UI/Popup/ImportButtons/PointImportButtonViz.ts b/src/UI/Popup/ImportButtons/PointImportButtonViz.ts
index 9333102682..b36724eb89 100644
--- a/src/UI/Popup/ImportButtons/PointImportButtonViz.ts
+++ b/src/UI/Popup/ImportButtons/PointImportButtonViz.ts
@@ -1,7 +1,5 @@
import { Feature, Point } from "geojson"
-import { UIEventSource } from "../../../Logic/UIEventSource"
-import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
-import BaseUIElement from "../../BaseUIElement"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../../SpecialVisualization"
import SvelteUIElement from "../../Base/SvelteUIElement"
import PointImportFlow from "./PointImportFlow.svelte"
import { PointImportFlowArguments, PointImportFlowState } from "./PointImportFlowState"
@@ -9,12 +7,14 @@ import { Utils } from "../../../Utils"
import { ImportFlowUtils } from "./ImportFlow"
import Translations from "../../i18n/Translations"
import { GeoOperations } from "../../../Logic/GeoOperations"
+import Tr from "../../Base/Tr.svelte"
+import { UIEventSource } from "../../../Logic/UIEventSource"
import { OsmTags } from "../../../Models/OsmFeature"
/**
* The wrapper to make the special visualisation for the PointImportFlow
*/
-export class PointImportButtonViz extends SpecialVisualization {
+export class PointImportButtonViz extends SpecialVisualizationSvelte {
public readonly funcName = "import_button"
public readonly docs: string =
"This button will copy the point from an external dataset into OpenStreetMap" +
@@ -47,29 +47,24 @@ export class PointImportButtonViz extends SpecialVisualization {
public needsUrls = []
group = "data_import"
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource,
- argument: string[],
- feature: Feature
- ): BaseUIElement {
+ constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement {
const to_point_index = this.args.findIndex((arg) => arg.name === "to_point")
- const summarizePointArg = argument[to_point_index].toLowerCase()
+ const summarizePointArg = args[to_point_index].toLowerCase()
if (feature.geometry.type !== "Point") {
if (summarizePointArg !== "no" && summarizePointArg !== "false") {
feature = GeoOperations.centerpoint(feature)
} else {
- return Translations.t.general.add.import.wrongType.SetClass("alert")
+ return new SvelteUIElement(Tr, { t: Translations.t.general.add.import.wrongType.SetClass("alert") })
}
}
- const baseArgs: PointImportFlowArguments = Utils.ParseVisArgs(this.args, argument)
- const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, baseArgs)
+ const baseArgs: PointImportFlowArguments = Utils.ParseVisArgs(this.args, args)
+ const tagsToApply = ImportFlowUtils.getTagsToApply(>tags, baseArgs)
const importFlow = new PointImportFlowState(
state,
>feature,
baseArgs,
tagsToApply,
- tagSource
+ tags
)
return new SvelteUIElement(PointImportFlow, {
diff --git a/src/UI/Popup/ImportButtons/WayImportButtonViz.ts b/src/UI/Popup/ImportButtons/WayImportButtonViz.ts
index 61272532f8..91106af08f 100644
--- a/src/UI/Popup/ImportButtons/WayImportButtonViz.ts
+++ b/src/UI/Popup/ImportButtons/WayImportButtonViz.ts
@@ -1,10 +1,12 @@
-import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
+import {
+ SpecialVisualisationParams,
+ SpecialVisualizationSvelte,
+ SpecialVisualizationUtils,
+} from "../../SpecialVisualization"
import { AutoAction } from "../AutoApplyButtonVis"
import { Feature, LineString, Polygon } from "geojson"
import { UIEventSource } from "../../../Logic/UIEventSource"
-import BaseUIElement from "../../BaseUIElement"
import { ImportFlowUtils } from "./ImportFlow"
-import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
import SvelteUIElement from "../../Base/SvelteUIElement"
import WayImportFlow from "./WayImportFlow.svelte"
import WayImportFlowState, { WayImportFlowArguments } from "./WayImportFlowState"
@@ -13,12 +15,11 @@ import ThemeConfig from "../../../Models/ThemeConfig/ThemeConfig"
import { Changes } from "../../../Logic/Osm/Changes"
import { IndexedFeatureSource } from "../../../Logic/FeatureSource/FeatureSource"
import FullNodeDatabaseSource from "../../../Logic/FeatureSource/TiledFeatureSource/FullNodeDatabaseSource"
-import { OsmTags } from "../../../Models/OsmFeature"
/**
* Wrapper around 'WayImportFlow' to make it a special visualisation
*/
-export default class WayImportButtonViz extends SpecialVisualization implements AutoAction {
+export default class WayImportButtonViz extends SpecialVisualizationSvelte implements AutoAction {
public readonly funcName: string = "import_way_button"
needsUrls = []
group = "data_import"
@@ -60,25 +61,20 @@ export default class WayImportButtonViz extends SpecialVisualization implements
public readonly supportsAutoAction = true
public readonly needsNodeDatabase = true
- constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource,
- argument: string[],
- feature: Feature,
- _: LayerConfig
- ): BaseUIElement {
+ constr({ state, tags, args, feature }: SpecialVisualisationParams): SvelteUIElement {
const geometry = feature.geometry
if (!(geometry.type == "LineString" || geometry.type === "Polygon")) {
- throw "Invalid type to import " + geometry.type
+ throw "Invalid type to import, expected linestring of polygon but got " + geometry.type
}
- const args: WayImportFlowArguments = Utils.ParseVisArgs(this.args, argument)
- const tagsToApply = ImportFlowUtils.getTagsToApply(tagSource, args)
+ const parsedArgs: WayImportFlowArguments = SpecialVisualizationUtils.parseArgs(this.args, args)
+ console.log("Parsed args are", parsedArgs)
+ const tagsToApply = ImportFlowUtils.getTagsToApply(tags, parsedArgs)
const importFlow = new WayImportFlowState(
state,
>feature,
- args,
+ parsedArgs,
tagsToApply,
- tagSource
+ tags,
)
return new SvelteUIElement(WayImportFlow, {
importFlow,
diff --git a/src/UI/Popup/LanguageElement/LanguageElement.ts b/src/UI/Popup/LanguageElement/LanguageElement.ts
index df0deecab5..4d95929e3c 100644
--- a/src/UI/Popup/LanguageElement/LanguageElement.ts
+++ b/src/UI/Popup/LanguageElement/LanguageElement.ts
@@ -1,46 +1,49 @@
-import { SpecialVisualization, SpecialVisualizationState } from "../../SpecialVisualization"
-import BaseUIElement from "../../BaseUIElement"
-import { UIEventSource } from "../../../Logic/UIEventSource"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../../SpecialVisualization"
import SvelteUIElement from "../../Base/SvelteUIElement"
-import { Feature } from "geojson"
-import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
import { default as LanguageElementSvelte } from "./LanguageElement.svelte"
-export class LanguageElement extends SpecialVisualization {
+export class LanguageElement extends SpecialVisualizationSvelte {
funcName: string = "language_chooser"
needsUrls = []
- docs: string | BaseUIElement =
+ docs: string =
"The language element allows to show and pick all known (modern) languages. The key can be set"
- args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [
+ args: { name: string; defaultValue?: string; doc: string; required?: boolean; type?: string }[] = [
{
name: "key",
required: true,
+ type:"key",
doc: "What key to use, e.g. `language`, `tactile_writing:braille:language`, ... If a language is supported, the language code will be appended to this key, resulting in `:nl=yes` if _nl_ is picked ",
},
{
name: "question",
required: true,
+ type: "translation",
doc: "What to ask if no questions are known",
},
{
name: "render_list_item",
+ type: "translation",
+
doc: "How a single language will be shown in the list of languages. Use `{language}` to indicate the language (which it must contain).",
defaultValue: "{language()}",
},
{
name: "render_single_language",
+ type: "translation",
doc: "What will be shown if the feature only supports a single language",
required: true,
},
{
+ type: "translation",
name: "render_all",
- doc: "The full rendering. Use `{list}` to show where the list of languages must come. Optional if mode=single",
+ doc: "The full rendering. U0se `{list}` to show where the list of languages must come. Optional if mode=single",
defaultValue: "{list()}",
},
{
name: "no_known_languages",
+ type: "translation",
doc: "The text that is shown if no languages are known for this key. If this text is omitted, the languages will be prompted instead",
},
]
@@ -59,14 +62,16 @@ export class LanguageElement extends SpecialVisualization {
`
constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- argument: string[],
- feature: Feature,
- layer: LayerConfig
- ): BaseUIElement {
+ {
+ state,
+ tags,
+ args,
+ feature,
+ layer,
+ }: SpecialVisualisationParams,
+ ): SvelteUIElement {
let [key, question, item_render, single_render, all_render, on_no_known_languages] =
- argument
+ args
if (item_render === undefined || item_render.trim() === "") {
item_render = "{language()}"
}
@@ -94,7 +99,7 @@ export class LanguageElement extends SpecialVisualization {
return new SvelteUIElement(LanguageElementSvelte, {
key,
- tags: tagSource,
+ tags,
state,
feature,
layer,
diff --git a/src/UI/Popup/MapillaryLinkVis.ts b/src/UI/Popup/MapillaryLinkVis.ts
index 048e99f94c..b3000a697c 100644
--- a/src/UI/Popup/MapillaryLinkVis.ts
+++ b/src/UI/Popup/MapillaryLinkVis.ts
@@ -1,7 +1,6 @@
import { GeoOperations } from "../../Logic/GeoOperations"
-import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource"
-import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
-import { Feature } from "geojson"
+import { ImmutableStore } from "../../Logic/UIEventSource"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization"
import SvelteUIElement from "../Base/SvelteUIElement"
import MapillaryLink from "../BigComponents/MapillaryLink.svelte"
@@ -20,12 +19,7 @@ export class MapillaryLinkVis extends SpecialVisualizationSvelte {
},
]
- public constr(
- state: SpecialVisualizationState,
- tagsSource: UIEventSource>,
- args: string[],
- feature: Feature
- ): SvelteUIElement {
+ public constr({ args, feature }: SpecialVisualisationParams): SvelteUIElement {
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
let zoom = Number(args[0])
if (isNaN(zoom)) {
diff --git a/src/UI/Popup/MinimapViz.svelte b/src/UI/Popup/MinimapViz.svelte
index e91ada4942..25b95242fb 100644
--- a/src/UI/Popup/MinimapViz.svelte
+++ b/src/UI/Popup/MinimapViz.svelte
@@ -1,6 +1,6 @@
diff --git a/src/UI/Popup/MultiApplyViz.ts b/src/UI/Popup/MultiApplyViz.ts
index 4a6254f58e..a44ef8c243 100644
--- a/src/UI/Popup/MultiApplyViz.ts
+++ b/src/UI/Popup/MultiApplyViz.ts
@@ -1,6 +1,6 @@
-import { Store, UIEventSource } from "../../Logic/UIEventSource"
+import { Store } from "../../Logic/UIEventSource"
import { MultiApplyParams } from "./MultiApply"
-import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization"
import SvelteUIElement from "../Base/SvelteUIElement"
import MultiApplyButton from "./MultiApplyButton.svelte"
@@ -19,7 +19,9 @@ export class MultiApplyViz extends SpecialVisualizationSvelte {
doc: "One key (or multiple keys, seperated by ';') of the attribute that should be copied onto the other features.",
required: true,
},
- { name: "text", doc: "The text to show on the button" },
+ { name: "text",
+ type: "translation",
+ 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",
@@ -34,17 +36,13 @@ export class MultiApplyViz extends SpecialVisualizationSvelte {
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: SpecialVisualizationState,
- tagsSource: UIEventSource>,
- args: string[]
- ): SvelteUIElement {
+ constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement {
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: Store = tagsSource.map((tags) => {
+ const featureIds: Store = tags.map((tags) => {
const ids = tags[featureIdsKey]
try {
if (ids === undefined) {
@@ -69,7 +67,7 @@ export class MultiApplyViz extends SpecialVisualizationSvelte {
text,
autoapply,
overwrite,
- tagsSource,
+ tagsSource: tags,
state,
}
return new SvelteUIElement(MultiApplyButton, { params })
diff --git a/src/UI/Popup/PlantNetDetectionViz.ts b/src/UI/Popup/PlantNetDetectionViz.ts
index fdfe5dc55f..1b2f2f697d 100644
--- a/src/UI/Popup/PlantNetDetectionViz.ts
+++ b/src/UI/Popup/PlantNetDetectionViz.ts
@@ -1,11 +1,11 @@
-import { Store, UIEventSource } from "../../Logic/UIEventSource"
+import { Store } from "../../Logic/UIEventSource"
import { ProvidedImage } from "../../Logic/ImageProviders/ImageProvider"
import Wikidata from "../../Logic/Web/Wikidata"
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
import { And } from "../../Logic/Tags/And"
import { Tag } from "../../Logic/Tags/Tag"
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
-import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization"
import SvelteUIElement from "../Base/SvelteUIElement"
import PlantNet from "../PlantNet/PlantNet.svelte"
import { default as PlantNetCode } from "../../Logic/Web/PlantNet"
@@ -31,16 +31,13 @@ export class PlantNetDetectionViz extends SpecialVisualizationSvelte {
args = [
{
name: "image_key",
+ type:"key",
defaultValue: AllImageProviders.defaultKeys.join(","),
doc: "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... Multiple values are allowed if ';'-separated ",
},
]
- public constr(
- state: SpecialVisualizationState,
- tags: UIEventSource>,
- args: string[]
- ): SvelteUIElement {
+ public constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement {
let imagePrefixes: string[] = undefined
if (args.length > 0) {
imagePrefixes = [].concat(...args.map((a) => a.split(",")))
diff --git a/src/UI/Popup/ShareLinkViz.ts b/src/UI/Popup/ShareLinkViz.ts
index cc0c86ccc3..15e602ec8e 100644
--- a/src/UI/Popup/ShareLinkViz.ts
+++ b/src/UI/Popup/ShareLinkViz.ts
@@ -1,6 +1,5 @@
-import { UIEventSource } from "../../Logic/UIEventSource"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
-import { SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization"
+import { SpecialVisualisationParams, SpecialVisualizationSvelte } from "../SpecialVisualization"
import SvelteUIElement from "../Base/SvelteUIElement"
import ShareButton from "../Base/ShareButton.svelte"
@@ -17,25 +16,25 @@ export class ShareLinkViz extends SpecialVisualizationSvelte {
},
{
name: "text",
+ type:"translation",
doc: "The text to show on the button. If none is given, will act as a titleIcon",
},
]
needsUrls = []
- public constr(
- state: SpecialVisualizationState,
- tagSource: UIEventSource>,
- args: string[]
+ public constr({
+ state,
+ tags,
+ args}:SpecialVisualisationParams
) {
const text = args[1]
const generateShareData = () => {
const title = state?.theme?.title?.txt ?? "MapComplete"
-
- const matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tagSource?.data)
+ const matchingLayer: LayerConfig = state?.theme?.getMatchingLayer(tags?.data)
let name =
- matchingLayer?.title?.GetRenderValue(tagSource.data)?.Subs(tagSource.data)?.txt ??
- tagSource.data?.name ??
+ matchingLayer?.title?.GetRenderValue(tags.data)?.Subs(tags.data)?.txt ??
+ tags.data?.name ??
"POI"
if (name) {
name = `${name} (${title})`
diff --git a/src/UI/Popup/TagRendering/SpecialTranslation.svelte b/src/UI/Popup/TagRendering/SpecialTranslation.svelte
index a9d5eff003..9686f3ff9f 100644
--- a/src/UI/Popup/TagRendering/SpecialTranslation.svelte
+++ b/src/UI/Popup/TagRendering/SpecialTranslation.svelte
@@ -51,7 +51,7 @@
{
try {
return specpart.func
- .constr(state, tags, specpart.args, feature, layer)
+ .constr({state, tags, args : specpart.args, feature, layer})
?.SetClass(specpart.style)
} catch (e) {
console.error(
diff --git a/src/UI/Popup/UploadToOsmViz.ts b/src/UI/Popup/UploadToOsmViz.ts
index ebabf95ff4..b4d9982ab6 100644
--- a/src/UI/Popup/UploadToOsmViz.ts
+++ b/src/UI/Popup/UploadToOsmViz.ts
@@ -1,4 +1,9 @@
-import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
+import {
+ SpecialVisualisationParams,
+ SpecialVisualization,
+ SpecialVisualizationState,
+ SpecialVisualizationSvelte,
+} from "../SpecialVisualization"
import { UIEventSource } from "../../Logic/UIEventSource"
import { GeoOperations } from "../../Logic/GeoOperations"
import Constants from "../../Models/Constants"
@@ -9,18 +14,14 @@ import { ServerSourceInfo } from "../../Models/SourceOverview"
/**
* Wrapper around 'UploadTraceToOsmUI'
*/
-export class UploadToOsmViz extends SpecialVisualization {
+export class UploadToOsmViz extends SpecialVisualizationSvelte {
funcName = "upload_to_osm"
docs =
"Uploads the GPS-history as GPX to OpenStreetMap.org; clears the history afterwards. The actual feature is ignored."
args = []
needsUrls: ServerSourceInfo[] = [Constants.osmAuthConfig]
- constr(
- state: SpecialVisualizationState,
- _: UIEventSource>,
- __: string[]
- ) {
+ constr({ state }: SpecialVisualisationParams): SvelteUIElement {
const locations = state.historicalUserLocations.features.data
return new SvelteUIElement(UploadTraceToOsmUI, {
state,
diff --git a/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts b/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts
index 13e7fbbddd..df7f1ac973 100644
--- a/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts
+++ b/src/UI/SpecialVisualisations/DataImportSpecialVisualisations.ts
@@ -1,4 +1,5 @@
import {
+ SpecialVisualisationParams,
SpecialVisualization,
SpecialVisualizationState,
SpecialVisualizationSvelte,
@@ -47,6 +48,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
args = [
{
name: "message",
+ type: "translation",
doc: "A message to show to the user",
},
{
@@ -56,6 +58,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
},
{
name: "message_confirm",
+ type: "translation",
doc: "What to show when the task is closed, either by the user or was already closed.",
},
{
@@ -65,17 +68,19 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
},
{
name: "maproulette_id",
+ type:"key",
doc: "The property name containing the maproulette id",
defaultValue: "mr_taskId",
},
{
name: "ask_feedback",
+ type: "translation",
doc: "If not an empty string, this will be used as question to ask some additional feedback. A text field will be added",
defaultValue: "",
},
]
- constr(state, tagsSource, args) {
+ constr({ state, tags, args }: SpecialVisualisationParams): SvelteUIElement {
let [message, image, message_closed, statusToSet, maproulette_id_key, askFeedback] = args
if (image === "") {
image = "confirm"
@@ -86,7 +91,7 @@ class MaprouletteSetStatusVis extends SpecialVisualizationSvelte {
statusToSet = statusToSet ?? "1"
return new SvelteUIElement(MaprouletteSetStatus, {
state,
- tags: tagsSource,
+ tags,
message,
image,
message_closed,
@@ -106,6 +111,7 @@ class LinkedDataFromWebsite extends SpecialVisualization {
{
name: "key",
defaultValue: "website",
+ type:"key",
doc: "Attempt to load ld+json from the specified URL. This can be in an embedded