Add countrycoder endpoint to connect sources

This commit is contained in:
Pieter Vander Vennet 2024-02-20 11:53:13 +01:00
parent ae7cc95727
commit bed8fb0bf9

View file

@ -3,7 +3,11 @@ import { FixedUiElement } from "./Base/FixedUiElement"
import BaseUIElement from "./BaseUIElement" import BaseUIElement from "./BaseUIElement"
import Title from "./Base/Title" import Title from "./Base/Title"
import Table from "./Base/Table" import Table from "./Base/Table"
import { RenderingSpecification, SpecialVisualization, SpecialVisualizationState } from "./SpecialVisualization" import {
RenderingSpecification,
SpecialVisualization,
SpecialVisualizationState,
} from "./SpecialVisualization"
import { HistogramViz } from "./Popup/HistogramViz" import { HistogramViz } from "./Popup/HistogramViz"
import { MinimapViz } from "./Popup/MinimapViz" import { MinimapViz } from "./Popup/MinimapViz"
import { ShareLinkViz } from "./Popup/ShareLinkViz" import { ShareLinkViz } from "./Popup/ShareLinkViz"
@ -114,7 +118,7 @@ class NearbyImageVis implements SpecialVisualization {
tags: UIEventSource<Record<string, string>>, tags: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const isOpen = args[0] === "open" const isOpen = args[0] === "open"
const readonly = args[1] === "readonly" const readonly = args[1] === "readonly"
@ -181,7 +185,7 @@ class StealViz implements SpecialVisualization {
selectedElement: otherFeature, selectedElement: otherFeature,
state, state,
layer, layer,
}), })
) )
} }
if (elements.length === 1) { if (elements.length === 1) {
@ -189,8 +193,8 @@ class StealViz implements SpecialVisualization {
} }
return new Combine(elements).SetClass("flex flex-col") return new Combine(elements).SetClass("flex flex-col")
}, },
[state.indexedFeatures.featuresById], [state.indexedFeatures.featuresById]
), )
) )
} }
@ -229,7 +233,7 @@ export class QuestionViz implements SpecialVisualization {
tags: UIEventSource<Record<string, string>>, tags: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const labels = args[0] const labels = args[0]
?.split(";") ?.split(";")
@ -272,7 +276,7 @@ export default class SpecialVisualizations {
defaultArg = "_empty string_" defaultArg = "_empty string_"
} }
return [arg.name, defaultArg, arg.doc] return [arg.name, defaultArg, arg.doc]
}), })
) )
: undefined, : undefined,
new Title("Example usage of " + viz.funcName, 4), new Title("Example usage of " + viz.funcName, 4),
@ -282,21 +286,21 @@ export default class SpecialVisualizations {
viz.funcName + viz.funcName +
"(" + "(" +
viz.args.map((arg) => arg.defaultValue).join(",") + viz.args.map((arg) => arg.defaultValue).join(",") +
")}`", ")}`"
).SetClass("literal-code"), ).SetClass("literal-code"),
]) ])
} }
public static constructSpecification( public static constructSpecification(
template: string, template: string,
extraMappings: SpecialVisualization[] = [], extraMappings: SpecialVisualization[] = []
): RenderingSpecification[] { ): RenderingSpecification[] {
return SpecialVisualisationUtils.constructSpecification(template, extraMappings) return SpecialVisualisationUtils.constructSpecification(template, extraMappings)
} }
public static HelpMessage() { public static HelpMessage() {
const helpTexts = SpecialVisualizations.specialVisualizations.map((viz) => const helpTexts = SpecialVisualizations.specialVisualizations.map((viz) =>
SpecialVisualizations.DocumentationFor(viz), SpecialVisualizations.DocumentationFor(viz)
) )
return new Combine([ return new Combine([
@ -330,10 +334,10 @@ export default class SpecialVisualizations {
}, },
}, },
null, null,
" ", " "
), )
).SetClass("code"), ).SetClass("code"),
"In other words: use `{ \"before\": ..., \"after\": ..., \"special\": {\"type\": ..., \"argname\": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)", 'In other words: use `{ "before": ..., "after": ..., "special": {"type": ..., "argname": ...argvalue...}`. The args are in the `special` block; an argvalue can be a string, a translation or another value. (Refer to class `RewriteSpecial` in case of problems)',
]).SetClass("flex flex-col"), ]).SetClass("flex flex-col"),
...helpTexts, ...helpTexts,
]).SetClass("flex flex-col") ]).SetClass("flex flex-col")
@ -342,7 +346,7 @@ export default class SpecialVisualizations {
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
public static renderExampleOfSpecial( public static renderExampleOfSpecial(
state: SpecialVisualizationState, state: SpecialVisualizationState,
s: SpecialVisualization, s: SpecialVisualization
): BaseUIElement { ): BaseUIElement {
const examples = const examples =
s.structuredExamples === undefined s.structuredExamples === undefined
@ -353,7 +357,7 @@ export default class SpecialVisualizations {
new UIEventSource<Record<string, string>>(e.feature.properties), new UIEventSource<Record<string, string>>(e.feature.properties),
e.args, e.args,
e.feature, e.feature,
undefined, undefined
) )
}) })
return new Combine([new Title(s.funcName), s.docs, ...examples]) return new Combine([new Title(s.funcName), s.docs, ...examples])
@ -395,7 +399,7 @@ export default class SpecialVisualizations {
assignTo: state.userRelatedState.language, assignTo: state.userRelatedState.language,
availableLanguages: state.layout.language, availableLanguages: state.layout.language,
preferredLanguages: state.osmConnection.userDetails.map( preferredLanguages: state.osmConnection.userDetails.map(
(ud) => ud.languages, (ud) => ud.languages
), ),
}) })
}, },
@ -420,7 +424,7 @@ export default class SpecialVisualizations {
constr( constr(
state: SpecialVisualizationState, state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>
): BaseUIElement { ): BaseUIElement {
return new VariableUiElement( return new VariableUiElement(
tagSource tagSource
@ -430,7 +434,7 @@ export default class SpecialVisualizations {
return new SplitRoadWizard(<WayId>id, state) return new SplitRoadWizard(<WayId>id, state)
} }
return undefined return undefined
}), })
) )
}, },
}, },
@ -444,7 +448,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
if (feature.geometry.type !== "Point") { if (feature.geometry.type !== "Point") {
return undefined return undefined
@ -467,7 +471,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
if (!layer.deletion) { if (!layer.deletion) {
return undefined return undefined
@ -495,7 +499,7 @@ export default class SpecialVisualizations {
state: SpecialVisualizationState, state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature
): BaseUIElement { ): BaseUIElement {
const [lon, lat] = GeoOperations.centerpointCoordinates(feature) const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
return new SvelteUIElement(CreateNewNote, { return new SvelteUIElement(CreateNewNote, {
@ -559,7 +563,7 @@ export default class SpecialVisualizations {
.map((tags) => tags[args[0]]) .map((tags) => tags[args[0]])
.map((wikidata) => { .map((wikidata) => {
wikidata = Utils.NoEmpty( wikidata = Utils.NoEmpty(
wikidata?.split(";")?.map((wd) => wd.trim()) ?? [], wikidata?.split(";")?.map((wd) => wd.trim()) ?? []
)[0] )[0]
const entry = Wikidata.LoadWikidataEntry(wikidata) const entry = Wikidata.LoadWikidataEntry(wikidata)
return new VariableUiElement( return new VariableUiElement(
@ -569,9 +573,9 @@ export default class SpecialVisualizations {
} }
const response = <WikidataResponse>e["success"] const response = <WikidataResponse>e["success"]
return Translation.fromMap(response.labels) return Translation.fromMap(response.labels)
}), })
) )
}), })
), ),
}, },
new MapillaryLinkVis(), new MapillaryLinkVis(),
@ -585,7 +589,7 @@ export default class SpecialVisualizations {
tags: UIEventSource<Record<string, string>>, tags: UIEventSource<Record<string, string>>,
_, _,
__, __,
layer: LayerConfig, layer: LayerConfig
) => new SvelteUIElement(AllTagsPanel, { tags, layer }), ) => new SvelteUIElement(AllTagsPanel, { tags, layer }),
}, },
{ {
@ -607,7 +611,7 @@ export default class SpecialVisualizations {
return new ImageCarousel( return new ImageCarousel(
AllImageProviders.LoadImagesFor(tags, imagePrefixes), AllImageProviders.LoadImagesFor(tags, imagePrefixes),
tags, tags,
state, state
) )
}, },
}, },
@ -663,7 +667,7 @@ export default class SpecialVisualizations {
{ {
nameKey: nameKey, nameKey: nameKey,
fallbackName, fallbackName,
}, }
) )
return new SvelteUIElement(StarsBarIcon, { return new SvelteUIElement(StarsBarIcon, {
score: reviews.average, score: reviews.average,
@ -696,7 +700,7 @@ export default class SpecialVisualizations {
{ {
nameKey: nameKey, nameKey: nameKey,
fallbackName, fallbackName,
}, }
) )
return new SvelteUIElement(ReviewForm, { reviews, state, tags, feature, layer }) return new SvelteUIElement(ReviewForm, { reviews, state, tags, feature, layer })
}, },
@ -728,7 +732,7 @@ export default class SpecialVisualizations {
{ {
nameKey: nameKey, nameKey: nameKey,
fallbackName, fallbackName,
}, }
) )
return new SvelteUIElement(AllReviews, { reviews, state, tags, feature, layer }) return new SvelteUIElement(AllReviews, { reviews, state, tags, feature, layer })
}, },
@ -753,7 +757,7 @@ export default class SpecialVisualizations {
doc: "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__", doc: "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__",
}, },
], ],
needsUrls: [Constants.countryCoderEndpoint],
example: 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)}`", "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<any>, args) => { constr: (state, tagSource: UIEventSource<any>, args) => {
@ -786,7 +790,7 @@ export default class SpecialVisualizations {
tags: UIEventSource<Record<string, string>>, tags: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): SvelteUIElement { ): SvelteUIElement {
const keyToUse = args[0] const keyToUse = args[0]
const prefix = args[1] const prefix = args[1]
@ -823,17 +827,17 @@ export default class SpecialVisualizations {
return undefined return undefined
} }
const allUnits: Unit[] = [].concat( const allUnits: Unit[] = [].concat(
...(state?.layout?.layers?.map((lyr) => lyr.units) ?? []), ...(state?.layout?.layers?.map((lyr) => lyr.units) ?? [])
) )
const unit = allUnits.filter((unit) => const unit = allUnits.filter((unit) =>
unit.isApplicableToKey(key), unit.isApplicableToKey(key)
)[0] )[0]
if (unit === undefined) { if (unit === undefined) {
return value return value
} }
const getCountry = () => tagSource.data._country const getCountry = () => tagSource.data._country
return unit.asHumanLongValue(value, getCountry) return unit.asHumanLongValue(value, getCountry)
}), })
) )
}, },
}, },
@ -850,7 +854,7 @@ export default class SpecialVisualizations {
new Combine([ new Combine([
t.downloadFeatureAsGeojson.SetClass("font-bold text-lg"), t.downloadFeatureAsGeojson.SetClass("font-bold text-lg"),
t.downloadGeoJsonHelper.SetClass("subtle"), t.downloadGeoJsonHelper.SetClass("subtle"),
]).SetClass("flex flex-col"), ]).SetClass("flex flex-col")
) )
.onClick(() => { .onClick(() => {
console.log("Exporting as Geojson") console.log("Exporting as Geojson")
@ -863,7 +867,7 @@ export default class SpecialVisualizations {
title + "_mapcomplete_export.geojson", title + "_mapcomplete_export.geojson",
{ {
mimetype: "application/vnd.geo+json", mimetype: "application/vnd.geo+json",
}, }
) )
}) })
.SetClass("w-full") .SetClass("w-full")
@ -899,7 +903,7 @@ export default class SpecialVisualizations {
constr: (state) => { constr: (state) => {
return new SubtleButton( return new SubtleButton(
Svg.delete_icon_svg().SetStyle("height: 1.5rem"), Svg.delete_icon_svg().SetStyle("height: 1.5rem"),
Translations.t.general.removeLocationHistory, Translations.t.general.removeLocationHistory
).onClick(() => { ).onClick(() => {
state.historicalUserLocations.features.setData([]) state.historicalUserLocations.features.setData([])
state.selectedElement.setData(undefined) state.selectedElement.setData(undefined)
@ -937,10 +941,10 @@ export default class SpecialVisualizations {
.filter((c) => c.text !== "") .filter((c) => c.text !== "")
.map( .map(
(c, i) => (c, i) =>
new NoteCommentElement(c, state, i, comments.length), new NoteCommentElement(c, state, i, comments.length)
), )
).SetClass("flex flex-col") ).SetClass("flex flex-col")
}), })
), ),
}, },
{ {
@ -974,7 +978,7 @@ export default class SpecialVisualizations {
tagsSource: UIEventSource<Record<string, string>>, tagsSource: UIEventSource<Record<string, string>>,
_: string[], _: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
) => ) =>
new VariableUiElement( new VariableUiElement(
tagsSource.map((tags) => { tagsSource.map((tags) => {
@ -992,7 +996,7 @@ export default class SpecialVisualizations {
feature, feature,
layer, layer,
}).SetClass("px-1") }).SetClass("px-1")
}), })
), ),
}, },
{ {
@ -1008,8 +1012,8 @@ export default class SpecialVisualizations {
let challenge = Stores.FromPromise( let challenge = Stores.FromPromise(
Utils.downloadJsonCached( Utils.downloadJsonCached(
`${Maproulette.defaultEndpoint}/challenge/${parentId}`, `${Maproulette.defaultEndpoint}/challenge/${parentId}`,
24 * 60 * 60 * 1000, 24 * 60 * 60 * 1000
), )
) )
return new VariableUiElement( return new VariableUiElement(
@ -1034,7 +1038,7 @@ export default class SpecialVisualizations {
} else { } else {
return [title, new List(listItems)] return [title, new List(listItems)]
} }
}), })
) )
}, },
docs: "Fetches the metadata of MapRoulette campaign that this task is part of and shows those details (namely `title`, `description` and `instruction`).\n\nThis reads the property `mr_challengeId` to detect the parent campaign.", docs: "Fetches the metadata of MapRoulette campaign that this task is part of and shows those details (namely `title`, `description` and `instruction`).\n\nThis reads the property `mr_challengeId` to detect the parent campaign.",
@ -1048,15 +1052,15 @@ export default class SpecialVisualizations {
"\n" + "\n" +
"```json\n" + "```json\n" +
"{\n" + "{\n" +
" \"id\": \"mark_duplicate\",\n" + ' "id": "mark_duplicate",\n' +
" \"render\": {\n" + ' "render": {\n' +
" \"special\": {\n" + ' "special": {\n' +
" \"type\": \"maproulette_set_status\",\n" + ' "type": "maproulette_set_status",\n' +
" \"message\": {\n" + ' "message": {\n' +
" \"en\": \"Mark as not found or false positive\"\n" + ' "en": "Mark as not found or false positive"\n' +
" },\n" + " },\n" +
" \"status\": \"2\",\n" + ' "status": "2",\n' +
" \"image\": \"close\"\n" + ' "image": "close"\n' +
" }\n" + " }\n" +
" }\n" + " }\n" +
"}\n" + "}\n" +
@ -1088,12 +1092,19 @@ export default class SpecialVisualizations {
{ {
name: "ask_feedback", name: "ask_feedback",
doc: "If not an empty string, this will be used as question to ask some additional feedback. A text field will be added", doc: "If not an empty string, this will be used as question to ask some additional feedback. A text field will be added",
defaultValue: "" defaultValue: "",
} },
], ],
constr: (state, tagsSource, args) => { constr: (state, tagsSource, args) => {
let [message, image, message_closed, statusToSet, maproulette_id_key, askFeedback] = args let [
message,
image,
message_closed,
statusToSet,
maproulette_id_key,
askFeedback,
] = args
if (image === "") { if (image === "") {
image = "confirm" image = "confirm"
} }
@ -1109,7 +1120,7 @@ export default class SpecialVisualizations {
message_closed, message_closed,
statusToSet, statusToSet,
maproulette_id_key, maproulette_id_key,
askFeedback askFeedback,
}) })
}, },
}, },
@ -1129,8 +1140,8 @@ export default class SpecialVisualizations {
const fsBboxed = new BBoxFeatureSourceForLayer(fs, bbox) const fsBboxed = new BBoxFeatureSourceForLayer(fs, bbox)
return new StatisticsPanel(fsBboxed) return new StatisticsPanel(fsBboxed)
}, },
[state.mapProperties.bounds], [state.mapProperties.bounds]
), )
) )
}, },
}, },
@ -1196,7 +1207,7 @@ export default class SpecialVisualizations {
constr( constr(
state: SpecialVisualizationState, state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
args: string[], args: string[]
): BaseUIElement { ): BaseUIElement {
let [text, href, classnames, download, ariaLabel] = args let [text, href, classnames, download, ariaLabel] = args
if (download === "") { if (download === "") {
@ -1208,13 +1219,16 @@ export default class SpecialVisualizations {
(tags) => (tags) =>
new SvelteUIElement(Link, { new SvelteUIElement(Link, {
text: Utils.SubstituteKeys(text, tags), text: Utils.SubstituteKeys(text, tags),
href: Utils.SubstituteKeys(href, tags).replaceAll(/ /g, "%20") /* Chromium based browsers eat the spaces */, href: Utils.SubstituteKeys(href, tags).replaceAll(
/ /g,
"%20"
) /* Chromium based browsers eat the spaces */,
classnames, classnames,
download: Utils.SubstituteKeys(download, tags), download: Utils.SubstituteKeys(download, tags),
ariaLabel: Utils.SubstituteKeys(ariaLabel, tags), ariaLabel: Utils.SubstituteKeys(ariaLabel, tags),
newTab, newTab,
}), })
), )
) )
}, },
}, },
@ -1236,7 +1250,7 @@ export default class SpecialVisualizations {
}, },
}, },
null, null,
" ", " "
) + ) +
"\n```", "\n```",
args: [ args: [
@ -1260,7 +1274,7 @@ export default class SpecialVisualizations {
featureTags: UIEventSource<Record<string, string>>, featureTags: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
) { ) {
const [key, tr, classesRaw] = args const [key, tr, classesRaw] = args
let classes = classesRaw ?? "" let classes = classesRaw ?? ""
@ -1285,7 +1299,7 @@ export default class SpecialVisualizations {
elements.push(subsTr) elements.push(subsTr)
} }
return elements return elements
}), })
) )
}, },
}, },
@ -1305,7 +1319,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new VariableUiElement( return new VariableUiElement(
tagSource.map((tags) => { tagSource.map((tags) => {
@ -1317,7 +1331,7 @@ export default class SpecialVisualizations {
console.error("Cannot create a translation for", v, "due to", e) console.error("Cannot create a translation for", v, "due to", e)
return JSON.stringify(v) return JSON.stringify(v)
} }
}), })
) )
}, },
}, },
@ -1337,7 +1351,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const key = argument[0] const key = argument[0]
const validator = new FediverseValidator() const validator = new FediverseValidator()
@ -1347,7 +1361,7 @@ export default class SpecialVisualizations {
.map((fediAccount) => { .map((fediAccount) => {
fediAccount = validator.reformat(fediAccount) fediAccount = validator.reformat(fediAccount)
const [_, username, host] = fediAccount.match( const [_, username, host] = fediAccount.match(
FediverseValidator.usernameAtServer, FediverseValidator.usernameAtServer
) )
const normalLink = new SvelteUIElement(Link, { const normalLink = new SvelteUIElement(Link, {
@ -1362,7 +1376,7 @@ export default class SpecialVisualizations {
] ]
console.log( console.log(
"LoggedinContributorMastodon", "LoggedinContributorMastodon",
loggedInContributorMastodon, loggedInContributorMastodon
) )
if (!loggedInContributorMastodon) { if (!loggedInContributorMastodon) {
return normalLink return normalLink
@ -1378,7 +1392,7 @@ export default class SpecialVisualizations {
newTab: true, newTab: true,
}).SetClass("button"), }).SetClass("button"),
]) ])
}), })
) )
}, },
}, },
@ -1398,7 +1412,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new FixedUiElement("{" + args[0] + "}") return new FixedUiElement("{" + args[0] + "}")
}, },
@ -1419,7 +1433,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const key = argument[0] ?? "value" const key = argument[0] ?? "value"
return new VariableUiElement( return new VariableUiElement(
@ -1439,10 +1453,10 @@ export default class SpecialVisualizations {
"Could not parse this tag: " + "Could not parse this tag: " +
JSON.stringify(value) + JSON.stringify(value) +
" due to " + " due to " +
e, e
).SetClass("alert") ).SetClass("alert")
} }
}), })
) )
}, },
}, },
@ -1463,7 +1477,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const giggityUrl = argument[0] const giggityUrl = argument[0]
return new SvelteUIElement(Giggity, { tags: tagSource, state, giggityUrl }) return new SvelteUIElement(Giggity, { tags: tagSource, state, giggityUrl })
@ -1479,12 +1493,12 @@ export default class SpecialVisualizations {
_: UIEventSource<Record<string, string>>, _: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const tags = (<ThemeViewState>( const tags = (<ThemeViewState>(
state state
)).geolocation.currentUserLocation.features.map( )).geolocation.currentUserLocation.features.map(
(features) => features[0]?.properties, (features) => features[0]?.properties
) )
return new Combine([ return new Combine([
new SvelteUIElement(OrientationDebugPanel, {}), new SvelteUIElement(OrientationDebugPanel, {}),
@ -1506,7 +1520,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new SvelteUIElement(MarkAsFavourite, { return new SvelteUIElement(MarkAsFavourite, {
tags: tagSource, tags: tagSource,
@ -1526,7 +1540,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new SvelteUIElement(MarkAsFavouriteMini, { return new SvelteUIElement(MarkAsFavouriteMini, {
tags: tagSource, tags: tagSource,
@ -1546,7 +1560,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new SvelteUIElement(DirectionIndicator, { state, feature }) return new SvelteUIElement(DirectionIndicator, { state, feature })
}, },
@ -1561,7 +1575,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
argument: string[], argument: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
return new VariableUiElement( return new VariableUiElement(
tagSource tagSource
@ -1583,9 +1597,9 @@ export default class SpecialVisualizations {
`${window.location.protocol}//${window.location.host}${window.location.pathname}?${layout}lat=${lat}&lon=${lon}&z=15` + `${window.location.protocol}//${window.location.host}${window.location.pathname}?${layout}lat=${lat}&lon=${lon}&z=15` +
`#${id}` `#${id}`
return new Img(new Qr(url).toImageElement(75)).SetStyle( return new Img(new Qr(url).toImageElement(75)).SetStyle(
"width: 75px", "width: 75px"
) )
}), })
) )
}, },
}, },
@ -1605,7 +1619,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const key = args[0] === "" ? "_direction:centerpoint" : args[0] const key = args[0] === "" ? "_direction:centerpoint" : args[0]
return new VariableUiElement( return new VariableUiElement(
@ -1616,11 +1630,11 @@ export default class SpecialVisualizations {
}) })
.mapD((value) => { .mapD((value) => {
const dir = GeoOperations.bearingToHuman( const dir = GeoOperations.bearingToHuman(
GeoOperations.parseBearing(value), GeoOperations.parseBearing(value)
) )
console.log("Human dir", dir) console.log("Human dir", dir)
return Translations.t.general.visualFeedback.directionsAbsolute[dir] return Translations.t.general.visualFeedback.directionsAbsolute[dir]
}), })
) )
}, },
}, },
@ -1655,7 +1669,7 @@ export default class SpecialVisualizations {
tagSource: UIEventSource<Record<string, string>>, tagSource: UIEventSource<Record<string, string>>,
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig, layer: LayerConfig
): BaseUIElement { ): BaseUIElement {
const url = args[0] const url = args[0]
const postprocessVelopark = args[2] === "velopark" const postprocessVelopark = args[2] === "velopark"
@ -1673,13 +1687,21 @@ export default class SpecialVisualizations {
}, },
{ {
funcName: "login_button", funcName: "login_button",
args: [ args: [],
],
docs: "Show a login button", docs: "Show a login button",
needsUrls: [], needsUrls: [],
constr(state: SpecialVisualizationState, tagSource: UIEventSource<Record<string, string>>, args: string[], feature: Feature, layer: LayerConfig): BaseUIElement { constr(
return new Toggle(undefined, state: SpecialVisualizationState,
new SvelteUIElement(LoginButton), state.osmConnection.isLoggedIn) tagSource: UIEventSource<Record<string, string>>,
args: string[],
feature: Feature,
layer: LayerConfig
): BaseUIElement {
return new Toggle(
undefined,
new SvelteUIElement(LoginButton),
state.osmConnection.isLoggedIn
)
}, },
}, },
] ]
@ -1693,7 +1715,7 @@ export default class SpecialVisualizations {
throw ( throw (
"Invalid special visualisation found: funcName is undefined for " + "Invalid special visualisation found: funcName is undefined for " +
invalid.map((sp) => sp.i).join(", ") + invalid.map((sp) => sp.i).join(", ") +
". Did you perhaps type \n funcName: \"funcname\" // type declaration uses COLON\ninstead of:\n funcName = \"funcName\" // value definition uses EQUAL" '. Did you perhaps type \n funcName: "funcname" // type declaration uses COLON\ninstead of:\n funcName = "funcName" // value definition uses EQUAL'
) )
} }