2020-10-14 12:15:09 +02:00
import Combine from "./Base/Combine"
2023-06-14 20:39:36 +02:00
import { FixedUiElement } from "./Base/FixedUiElement"
2021-06-11 22:51:45 +02:00
import BaseUIElement from "./BaseUIElement"
2021-06-21 00:19:19 +02:00
import Title from "./Base/Title"
2024-04-13 02:40:21 +02:00
import {
RenderingSpecification ,
SpecialVisualization ,
2024-06-17 04:27:08 +02:00
SpecialVisualizationState
2024-04-13 02:40:21 +02:00
} from "./SpecialVisualization"
2023-06-14 20:39:36 +02:00
import { HistogramViz } from "./Popup/HistogramViz"
import { MinimapViz } from "./Popup/MinimapViz"
import { ShareLinkViz } from "./Popup/ShareLinkViz"
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
import { MultiApplyViz } from "./Popup/MultiApplyViz"
2023-12-26 22:30:27 +01:00
import { AddNoteCommentViz } from "./Popup/Notes/AddNoteCommentViz"
2023-06-14 20:39:36 +02:00
import { PlantNetDetectionViz } from "./Popup/PlantNetDetectionViz"
2022-11-02 13:47:34 +01:00
import TagApplyButton from "./Popup/TagApplyButton"
2023-12-26 22:30:27 +01:00
import { CloseNoteButton } from "./Popup/Notes/CloseNoteButton"
2023-06-14 20:39:36 +02:00
import { MapillaryLinkVis } from "./Popup/MapillaryLinkVis"
2024-01-31 12:09:15 +01:00
import { ImmutableStore , Store , Stores , UIEventSource } from "../Logic/UIEventSource"
2023-03-24 19:21:15 +01:00
import AllTagsPanel from "./Popup/AllTagsPanel.svelte"
2022-11-02 13:47:34 +01:00
import AllImageProviders from "../Logic/ImageProviders/AllImageProviders"
2023-06-14 20:39:36 +02:00
import { ImageCarousel } from "./Image/ImageCarousel"
import { VariableUiElement } from "./Base/VariableUIElement"
import { Utils } from "../Utils"
import Wikidata , { WikidataResponse } from "../Logic/Web/Wikidata"
import { Translation } from "./i18n/Translation"
2022-11-02 13:47:34 +01:00
import Translations from "./i18n/Translations"
import OpeningHoursVisualization from "./OpeningHours/OpeningHoursVisualization"
2023-06-14 20:39:36 +02:00
import { SubtleButton } from "./Base/SubtleButton"
2023-12-26 22:30:27 +01:00
import NoteCommentElement from "./Popup/Notes/NoteCommentElement"
2022-11-02 13:47:34 +01:00
import List from "./Base/List"
import StatisticsPanel from "./BigComponents/StatisticsPanel"
import AutoApplyButton from "./Popup/AutoApplyButton"
2024-01-25 03:13:18 +01:00
import { LanguageElement } from "./Popup/LanguageElement/LanguageElement"
2023-01-21 23:58:14 +01:00
import FeatureReviews from "../Logic/Web/MangroveReviews"
2024-05-13 18:45:43 +02:00
import Maproulette , { MaprouletteTask } from "../Logic/Maproulette"
2023-02-15 18:24:08 +01:00
import SvelteUIElement from "./Base/SvelteUIElement"
2023-06-14 20:39:36 +02:00
import { BBoxFeatureSourceForLayer } from "../Logic/FeatureSource/Sources/TouchesBboxFeatureSource"
2024-04-22 18:16:19 +02:00
import { Feature , GeoJsonProperties } from "geojson"
2023-06-14 20:39:36 +02:00
import { GeoOperations } from "../Logic/GeoOperations"
2023-12-26 22:30:27 +01:00
import CreateNewNote from "./Popup/Notes/CreateNewNote.svelte"
2023-04-06 01:33:08 +02:00
import AddNewPoint from "./Popup/AddNewPoint/AddNewPoint.svelte"
2023-04-07 02:13:57 +02:00
import UserProfile from "./BigComponents/UserProfile.svelte"
2023-04-13 22:44:35 +02:00
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig"
2023-06-14 20:39:36 +02:00
import { ExportAsGpxViz } from "./Popup/ExportAsGpxViz"
2023-04-21 16:02:36 +02:00
import WikipediaPanel from "./Wikipedia/WikipediaPanel.svelte"
2023-06-14 20:39:36 +02:00
import TagRenderingEditable from "./Popup/TagRendering/TagRenderingEditable.svelte"
import { PointImportButtonViz } from "./Popup/ImportButtons/PointImportButtonViz"
import WayImportButtonViz from "./Popup/ImportButtons/WayImportButtonViz"
import ConflateImportButtonViz from "./Popup/ImportButtons/ConflateImportButtonViz"
import DeleteWizard from "./Popup/DeleteFlow/DeleteWizard.svelte"
import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"
2023-08-10 16:25:25 +02:00
import FediverseValidator from "./InputElement/Validators/FediverseValidator"
2023-09-15 01:53:50 +02:00
import SendEmail from "./Popup/SendEmail.svelte"
2023-09-28 23:50:27 +02:00
import UploadImage from "./Image/UploadImage.svelte"
2023-09-27 22:21:35 +02:00
import { Imgur } from "../Logic/ImageProviders/Imgur"
import Constants from "../Models/Constants"
import { MangroveReviews } from "mangrove-reviews-typescript"
import Wikipedia from "../Logic/Web/Wikipedia"
import NearbyImagesSearch from "../Logic/Web/NearbyImagesSearch"
2023-09-28 23:50:27 +02:00
import AllReviews from "./Reviews/AllReviews.svelte"
import StarsBarIcon from "./Reviews/StarsBarIcon.svelte"
import ReviewForm from "./Reviews/ReviewForm.svelte"
2023-10-10 01:52:02 +02:00
import Questionbox from "./Popup/TagRendering/Questionbox.svelte"
2023-10-22 01:30:05 +02:00
import { TagUtils } from "../Logic/Tags/TagUtils"
2023-11-11 14:35:45 +01:00
import Giggity from "./BigComponents/Giggity.svelte"
2023-11-12 10:14:51 +01:00
import ThemeViewState from "../Models/ThemeViewState"
2023-11-19 01:05:15 +01:00
import LanguagePicker from "./InputElement/LanguagePicker.svelte"
2023-11-19 04:38:34 +01:00
import LogoutButton from "./Base/LogoutButton.svelte"
import OpenJosm from "./Base/OpenJosm.svelte"
2023-11-22 19:39:19 +01:00
import MarkAsFavourite from "./Popup/MarkAsFavourite.svelte"
import MarkAsFavouriteMini from "./Popup/MarkAsFavouriteMini.svelte"
2023-12-04 03:32:25 +01:00
import NextChangeViz from "./OpeningHours/NextChangeViz.svelte"
2023-12-05 18:35:18 +01:00
import NearbyImages from "./Image/NearbyImages.svelte"
import NearbyImagesCollapsed from "./Image/NearbyImagesCollapsed.svelte"
2023-12-07 21:57:20 +01:00
import MoveWizard from "./Popup/MoveWizard.svelte"
2023-12-12 03:46:51 +01:00
import { Unit } from "../Models/Unit"
2023-12-14 18:25:35 +01:00
import Link from "./Base/Link.svelte"
2023-12-16 01:29:42 +01:00
import OrientationDebugPanel from "./Debug/OrientationDebugPanel.svelte"
2023-12-09 16:52:15 +01:00
import MaprouletteSetStatus from "./MapRoulette/MaprouletteSetStatus.svelte"
2023-12-24 05:01:10 +01:00
import DirectionIndicator from "./Base/DirectionIndicator.svelte"
import Img from "./Base/Img"
import Qr from "../Utils/Qr"
2024-01-13 05:24:56 +01:00
import ComparisonTool from "./Comparison/ComparisonTool.svelte"
2024-01-25 03:13:18 +01:00
import SpecialTranslation from "./Popup/TagRendering/SpecialTranslation.svelte"
2024-01-25 13:41:33 +01:00
import SpecialVisualisationUtils from "./SpecialVisualisationUtils"
2024-02-14 12:20:29 +01:00
import LoginButton from "./Base/LoginButton.svelte"
import Toggle from "./Input/Toggle"
2024-02-20 16:53:26 +01:00
import ImportReviewIdentity from "./Reviews/ImportReviewIdentity.svelte"
2024-02-26 02:24:46 +01:00
import LinkedDataLoader from "../Logic/Web/LinkedDataLoader"
2024-03-04 15:31:09 +01:00
import SplitRoadWizard from "./Popup/SplitRoadWizard.svelte"
2024-04-10 15:29:48 +02:00
import DynLink from "./Base/DynLink.svelte"
2024-05-06 15:18:29 +02:00
import Locale from "./i18n/Locale"
import LanguageUtils from "../Utils/LanguageUtils"
2024-05-07 00:42:52 +02:00
import MarkdownUtils from "../Utils/MarkdownUtils"
2024-06-16 19:00:43 +02:00
import ArrowDownTray from "@babeard/svelte-heroicons/mini/ArrowDownTray"
import Trash from "@babeard/svelte-heroicons/mini/Trash"
2024-06-17 04:27:08 +02:00
import NothingKnown from "./Popup/NothingKnown.svelte"
2022-05-06 12:41:24 +02:00
2023-04-13 22:44:35 +02:00
class NearbyImageVis implements SpecialVisualization {
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
args : { name : string ; defaultValue? : string ; doc : string ; required? : boolean } [ ] = [
{
name : "mode" ,
2023-09-16 03:09:14 +02:00
defaultValue : "closed" ,
2024-06-17 04:27:08 +02:00
doc : "Either `open` or `closed`. If `open`, then the image carousel will always be shown"
2023-04-13 22:44:35 +02:00
} ,
2024-01-17 18:08:14 +01:00
{
name : "readonly" ,
required : false ,
2024-06-17 04:27:08 +02:00
doc : "If 'readonly', will not show the 'link'-button"
}
2023-04-13 22:44:35 +02:00
]
docs =
"A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
funcName = "nearby_images"
2023-09-27 22:21:35 +02:00
needsUrls = NearbyImagesSearch . apiUrls
2023-12-31 20:57:45 +01:00
svelteBased = true
2023-11-11 14:35:45 +01:00
2023-04-13 22:44:35 +02:00
constr (
state : SpecialVisualizationState ,
2023-09-16 02:30:01 +02:00
tags : UIEventSource < Record < string , string > > ,
2023-04-13 22:44:35 +02:00
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-04-13 22:44:35 +02:00
) : BaseUIElement {
2023-09-16 03:09:14 +02:00
const isOpen = args [ 0 ] === "open"
2024-01-17 18:08:14 +01:00
const readonly = args [ 1 ] === "readonly"
2023-04-13 22:44:35 +02:00
const [ lon , lat ] = GeoOperations . centerpointCoordinates ( feature )
2023-09-16 03:09:14 +02:00
return new SvelteUIElement ( isOpen ? NearbyImages : NearbyImagesCollapsed , {
tags ,
state ,
lon ,
lat ,
feature ,
layer ,
2024-06-17 04:27:08 +02:00
linkable : ! readonly
2023-04-13 22:44:35 +02:00
} )
}
}
class StealViz implements SpecialVisualization {
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
funcName = "steal"
docs = "Shows a tagRendering from a different object as if this was the object itself"
args = [
{
name : "featureId" ,
doc : "The key of the attribute which contains the id of the feature from which to use the tags" ,
2024-06-17 04:27:08 +02:00
required : true
2023-04-13 22:44:35 +02:00
} ,
{
name : "tagRenderingId" ,
doc : "The layer-id and tagRenderingId to render. Can be multiple value if ';'-separated (in which case every value must also contain the layerId, e.g. `layerId.tagRendering0; layerId.tagRendering1`). Note: this can cause layer injection" ,
2024-06-17 04:27:08 +02:00
required : true
}
2023-04-13 22:44:35 +02:00
]
2023-09-27 22:21:35 +02:00
needsUrls = [ ]
2023-12-31 20:57:45 +01:00
svelteBased = true
2023-04-14 02:42:57 +02:00
2023-04-13 22:44:35 +02:00
constr ( state : SpecialVisualizationState , featureTags , args ) {
const [ featureIdKey , layerAndtagRenderingIds ] = args
const tagRenderings : [ LayerConfig , TagRenderingConfig ] [ ] = [ ]
for ( const layerAndTagRenderingId of layerAndtagRenderingIds . split ( ";" ) ) {
const [ layerId , tagRenderingId ] = layerAndTagRenderingId . trim ( ) . split ( "." )
const layer = state . layout . layers . find ( ( l ) = > l . id === layerId )
const tagRendering = layer . tagRenderings . find ( ( tr ) = > tr . id === tagRenderingId )
tagRenderings . push ( [ layer , tagRendering ] )
}
if ( tagRenderings . length === 0 ) {
throw "Could not create stolen tagrenddering: tagRenderings not found"
}
return new VariableUiElement (
2023-06-14 20:39:36 +02:00
featureTags . map (
( tags ) = > {
const featureId = tags [ featureIdKey ]
if ( featureId === undefined ) {
return undefined
}
const otherTags = state . featureProperties . getStore ( featureId )
const otherFeature = state . indexedFeatures . featuresById . data . get ( featureId )
const elements : BaseUIElement [ ] = [ ]
for ( const [ layer , tagRendering ] of tagRenderings ) {
elements . push (
new SvelteUIElement ( TagRenderingEditable , {
config : tagRendering ,
tags : otherTags ,
selectedElement : otherFeature ,
state ,
2024-06-17 04:27:08 +02:00
layer
2024-04-05 17:49:31 +02:00
} )
2023-06-14 20:39:36 +02:00
)
}
if ( elements . length === 1 ) {
return elements [ 0 ]
}
return new Combine ( elements ) . SetClass ( "flex flex-col" )
} ,
2024-04-05 17:49:31 +02:00
[ state . indexedFeatures . featuresById ]
)
2023-04-13 22:44:35 +02:00
)
}
getLayerDependencies ( args ) : string [ ] {
2024-04-12 15:33:15 +02:00
const [ , tagRenderingId ] = args
2023-04-13 22:44:35 +02:00
if ( tagRenderingId . indexOf ( "." ) < 0 ) {
throw "Error: argument 'layerId.tagRenderingId' of special visualisation 'steal' should contain a dot"
}
2024-04-12 15:33:15 +02:00
const [ layerId ] = tagRenderingId . split ( "." )
2023-04-13 22:44:35 +02:00
return [ layerId ]
}
}
2023-04-14 02:42:57 +02:00
2023-10-06 03:34:26 +02:00
/ * *
* Thin wrapper around QuestionBox . svelte to include it into the special Visualisations
* /
export class QuestionViz implements SpecialVisualization {
funcName = "questions"
needsUrls = [ ]
docs =
2023-10-10 01:52:02 +02:00
"The special element which shows the questions which are unkown. Added by default if not yet there"
2023-10-06 03:34:26 +02:00
args = [
{
name : "labels" ,
2024-06-17 04:27:08 +02:00
doc : "One or more ';'-separated labels. If these are given, only questions with these labels will be given. Use `unlabeled` for all questions that don't have an explicit label. If none given, all questions will be shown"
2023-10-06 03:34:26 +02:00
} ,
{
name : "blacklisted-labels" ,
2024-06-17 04:27:08 +02:00
doc : "One or more ';'-separated labels of questions which should _not_ be included"
}
2023-10-06 03:34:26 +02:00
]
2023-12-31 20:57:45 +01:00
svelteBased = true
2023-10-06 03:34:26 +02:00
constr (
2023-10-10 01:52:02 +02:00
state : SpecialVisualizationState ,
tags : UIEventSource < Record < string , string > > ,
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-10-06 03:34:26 +02:00
) : BaseUIElement {
const labels = args [ 0 ]
2023-10-10 01:52:02 +02:00
? . split ( ";" )
? . map ( ( s ) = > s . trim ( ) )
? . filter ( ( s ) = > s !== "" )
2023-10-06 03:34:26 +02:00
const blacklist = args [ 1 ]
2023-10-10 01:52:02 +02:00
? . split ( ";" )
? . map ( ( s ) = > s . trim ( ) )
? . filter ( ( s ) = > s !== "" )
2023-10-06 03:34:26 +02:00
return new SvelteUIElement ( Questionbox , {
layer ,
tags ,
selectedElement : feature ,
state ,
onlyForLabels : labels ,
2024-06-17 04:27:08 +02:00
notForLabels : blacklist
2023-12-31 20:57:45 +01:00
} ) . SetClass ( "w-full" )
2023-10-06 03:34:26 +02:00
}
}
2020-10-09 20:10:21 +02:00
export default class SpecialVisualizations {
2022-11-02 13:47:34 +01:00
public static specialVisualizations : SpecialVisualization [ ] = SpecialVisualizations . initList ( )
2021-12-12 02:59:24 +01:00
2024-05-07 00:42:52 +02:00
public static DocumentationFor ( viz : string | SpecialVisualization ) : string {
2023-02-14 00:09:04 +01:00
if ( typeof viz === "string" ) {
viz = SpecialVisualizations . specialVisualizations . find ( ( sv ) = > sv . funcName === viz )
}
if ( viz === undefined ) {
2024-05-07 00:42:52 +02:00
return ""
2023-02-14 00:09:04 +01:00
}
2024-06-16 16:06:26 +02:00
const example =
viz . example ? ?
"`{" + viz . funcName + "(" + viz . args . map ( ( arg ) = > arg . defaultValue ) . join ( "," ) + ")}`"
2024-05-07 00:42:52 +02:00
return [
"### " + viz . funcName ,
2023-02-14 00:09:04 +01:00
viz . docs ,
viz . args . length > 0
2024-05-07 00:42:52 +02:00
? MarkdownUtils . table (
2024-06-17 04:27:08 +02:00
[ "name" , "default" , "description" ] ,
viz . args . map ( ( arg ) = > {
let defaultArg = arg . defaultValue ? ? "_undefined_"
if ( defaultArg == "" ) {
defaultArg = "_empty string_"
}
return [ arg . name , defaultArg , arg . doc ]
} )
)
2023-02-14 00:09:04 +01:00
: undefined ,
2024-05-07 00:42:52 +02:00
"#### Example usage of " + viz . funcName ,
2024-06-17 04:27:08 +02:00
"<code>" + example + "</code>"
2024-05-07 00:42:52 +02:00
] . join ( "\n\n" )
2023-02-14 00:09:04 +01:00
}
2024-01-25 13:41:33 +01:00
public static constructSpecification (
template : string ,
2024-04-05 17:49:31 +02:00
extraMappings : SpecialVisualization [ ] = [ ]
2024-01-25 13:41:33 +01:00
) : RenderingSpecification [ ] {
return SpecialVisualisationUtils . constructSpecification ( template , extraMappings )
}
2024-02-14 12:20:29 +01:00
2024-05-07 00:42:52 +02:00
public static HelpMessage ( ) : string {
const helpTexts : string [ ] = SpecialVisualizations . specialVisualizations . map ( ( viz ) = >
2024-04-05 17:49:31 +02:00
SpecialVisualizations . DocumentationFor ( viz )
2023-02-14 00:09:04 +01:00
)
2024-05-07 00:42:52 +02:00
const firstPart = new Combine ( [
new Title ( "Special tag renderings" , 1 ) ,
2023-02-14 00:09:04 +01:00
2024-05-07 00:42:52 +02:00
"In a tagrendering, some special values are substituted by an advanced UI-element. This allows advanced features and visualizations to be reused by custom themes or even to query third-party API's." ,
2024-06-17 04:27:08 +02:00
"General usage is `{func_name()}`, `{func_name(arg, someotherarg)}` or `{func_name(args):cssClasses}`. Note that you _do not_ need to use quotes around your arguments, the comma is enough to separate them. This also implies you cannot use a comma in your args" ,
2024-05-07 00:42:52 +02:00
new Title ( "Using expanded syntax" , 4 ) ,
` Instead of using \` {"render": {"en": "{some_special_visualisation(some_arg, some other really long message, more args)} , "nl": "{some_special_visualisation(some_arg, een boodschap in een andere taal, more args)}} \` , one can also write ` ,
new FixedUiElement (
JSON . stringify (
{
render : {
special : {
type : "some_special_visualisation" ,
argname : "some_arg" ,
message : {
en : "some other really long message" ,
2024-06-17 04:27:08 +02:00
nl : "een boodschap in een andere taal"
2024-04-13 02:40:21 +02:00
} ,
2024-06-17 04:27:08 +02:00
other_arg_name : "more args"
2024-04-13 02:40:21 +02:00
} ,
2024-05-07 00:42:52 +02:00
before : {
en : "Some text to prefix before the special element (e.g. a title)" ,
2024-06-17 04:27:08 +02:00
nl : "Een tekst om voor het element te zetten (bv. een titel)"
2024-05-07 00:42:52 +02:00
} ,
after : {
2024-06-17 04:27:08 +02:00
en : "Some text to put after the element, e.g. a footer"
}
}
2024-05-07 00:42:52 +02:00
} ,
null ,
" "
)
) . SetClass ( "code" ) ,
2024-06-17 04:27:08 +02:00
"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)"
2024-06-16 16:06:26 +02:00
] )
. SetClass ( "flex flex-col" )
. AsMarkdown ( )
console . log ( ">>> " , helpTexts . join ( "\n\n" ) )
2024-05-07 00:42:52 +02:00
return firstPart + "\n\n" + helpTexts . join ( "\n\n" )
2023-02-14 00:09:04 +01:00
}
2023-04-06 01:33:08 +02:00
// noinspection JSUnusedGlobalSymbols
public static renderExampleOfSpecial (
state : SpecialVisualizationState ,
2024-04-05 17:49:31 +02:00
s : SpecialVisualization
2023-04-06 01:33:08 +02:00
) : BaseUIElement {
const examples =
s . structuredExamples === undefined
? [ ]
: s . structuredExamples ( ) . map ( ( e ) = > {
2024-06-17 04:27:08 +02:00
return s . constr (
state ,
new UIEventSource < Record < string , string > > ( e . feature . properties ) ,
e . args ,
e . feature ,
undefined
)
} )
2023-04-06 01:33:08 +02:00
return new Combine ( [ new Title ( s . funcName ) , s . docs , . . . examples ] )
}
2022-11-02 13:47:34 +01:00
private static initList ( ) : SpecialVisualization [ ] {
2022-01-08 04:22:50 +01:00
const specialVisualizations : SpecialVisualization [ ] = [
2023-03-31 03:28:11 +02:00
new QuestionViz ( ) ,
2023-04-02 02:59:20 +02:00
{
funcName : "add_new_point" ,
docs : "An element which allows to add a new point on the 'last_click'-location. Only makes sense in the layer `last_click`" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-06 01:33:08 +02:00
constr ( state : SpecialVisualizationState , _ , __ , feature ) : BaseUIElement {
2024-04-12 15:33:15 +02:00
const [ lon , lat ] = GeoOperations . centerpointCoordinates ( feature )
2023-04-06 01:33:08 +02:00
return new SvelteUIElement ( AddNewPoint , {
state ,
2024-06-17 04:27:08 +02:00
coordinate : { lon , lat }
2023-11-18 20:13:24 +01:00
} ) . SetClass ( "w-full h-full overflow-auto" )
2024-06-17 04:27:08 +02:00
}
2023-04-02 02:59:20 +02:00
} ,
2023-04-07 02:13:57 +02:00
{
funcName : "user_profile" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-07 02:13:57 +02:00
docs : "A component showing information about the currently logged in user (username, profile description, profile picture + link to edit them). Mostly meant to be used in the 'user-settings'" ,
constr ( state : SpecialVisualizationState ) : BaseUIElement {
return new SvelteUIElement ( UserProfile , {
2024-06-17 04:27:08 +02:00
osmConnection : state.osmConnection
2023-04-07 02:13:57 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2023-04-07 02:13:57 +02:00
} ,
{
funcName : "language_picker" ,
args : [ ] ,
docs : "A component to set the language of the user interface" ,
constr ( state : SpecialVisualizationState ) : BaseUIElement {
2024-05-06 15:18:29 +02:00
return new VariableUiElement (
2024-06-16 16:06:26 +02:00
Locale . showLinkToWeblate . map ( ( showTranslations ) = > {
const languages = showTranslations
? LanguageUtils . usedLanguagesSorted
: state . layout . language
2024-05-06 15:18:29 +02:00
return new SvelteUIElement ( LanguagePicker , {
assignTo : state.userRelatedState.language ,
availableLanguages : languages ,
preferredLanguages : state.osmConnection.userDetails.map (
( ud ) = > ud . languages
2024-06-17 04:27:08 +02:00
)
2024-05-06 15:18:29 +02:00
} )
} )
)
2024-06-17 04:27:08 +02:00
}
2023-04-07 02:13:57 +02:00
} ,
{
funcName : "logout" ,
args : [ ] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Constants . osmAuthConfig . url ] ,
2023-04-07 02:13:57 +02:00
docs : "Shows a button where the user can log out" ,
2023-12-31 20:57:45 +01:00
2023-04-07 02:13:57 +02:00
constr ( state : SpecialVisualizationState ) : BaseUIElement {
2023-11-19 04:38:34 +01:00
return new SvelteUIElement ( LogoutButton , { osmConnection : state.osmConnection } )
2024-06-17 04:27:08 +02:00
}
2023-04-07 02:13:57 +02:00
} ,
2022-10-28 04:33:05 +02:00
new HistogramViz ( ) ,
new StealViz ( ) ,
new MinimapViz ( ) ,
2023-04-14 02:42:57 +02:00
{
funcName : "split_button" ,
docs : "Adds a button which allows to split a way" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-14 02:42:57 +02:00
constr (
state : SpecialVisualizationState ,
2024-04-05 17:49:31 +02:00
tagSource : UIEventSource < Record < string , string > >
2023-04-14 02:42:57 +02:00
) : BaseUIElement {
return new VariableUiElement (
tagSource
. map ( ( tags ) = > tags . id )
2023-04-20 01:52:23 +02:00
. map ( ( id ) = > {
if ( id . startsWith ( "way/" ) ) {
2024-03-04 15:31:09 +01:00
return new SvelteUIElement ( SplitRoadWizard , { id , state } )
2023-04-20 01:52:23 +02:00
}
return undefined
2024-04-05 17:49:31 +02:00
} )
2023-04-14 02:42:57 +02:00
)
2024-06-17 04:27:08 +02:00
}
2023-04-14 02:42:57 +02:00
} ,
{
funcName : "move_button" ,
docs : "Adds a button which allows to move the object to another location. The config will be read from the layer config" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-14 02:42:57 +02:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-04-14 02:42:57 +02:00
) : BaseUIElement {
if ( feature . geometry . type !== "Point" ) {
return undefined
}
2023-12-07 21:57:20 +01:00
return new SvelteUIElement ( MoveWizard , {
2023-04-14 02:42:57 +02:00
state ,
2023-12-07 21:57:20 +01:00
featureToMove : feature ,
2024-06-17 04:27:08 +02:00
layer
2023-12-07 21:57:20 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2023-04-14 02:42:57 +02:00
} ,
{
funcName : "delete_button" ,
docs : "Adds a button which allows to delete the object at this location. The config will be read from the layer config" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-14 02:42:57 +02:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-04-14 02:42:57 +02:00
) : BaseUIElement {
2023-11-30 00:39:55 +01:00
if ( ! layer . deletion ) {
return undefined
}
2023-06-01 23:40:05 +02:00
return new SvelteUIElement ( DeleteWizard , {
tags : tagSource ,
deleteConfig : layer.deletion ,
state ,
feature ,
2024-06-17 04:27:08 +02:00
layer
2024-06-16 19:00:43 +02:00
} ) . SetClass ( "p-0 m-0" )
2024-06-17 04:27:08 +02:00
}
2023-04-14 02:42:57 +02:00
} ,
2022-11-02 13:47:34 +01:00
new ShareLinkViz ( ) ,
2023-04-20 18:58:31 +02:00
new ExportAsGpxViz ( ) ,
2022-10-28 04:33:05 +02:00
new UploadToOsmViz ( ) ,
new MultiApplyViz ( ) ,
new AddNoteCommentViz ( ) ,
2023-04-06 01:33:08 +02:00
{
funcName : "open_note" ,
args : [ ] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Constants . osmAuthConfig . url ] ,
2023-04-06 01:33:08 +02:00
docs : "Creates a new map note on the given location. This options is placed in the 'last_click'-popup automatically if the 'notes'-layer is enabled" ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
2024-04-05 17:49:31 +02:00
feature : Feature
2023-04-06 01:33:08 +02:00
) : BaseUIElement {
const [ lon , lat ] = GeoOperations . centerpointCoordinates ( feature )
2023-10-15 10:55:56 +02:00
return new SvelteUIElement ( CreateNewNote , {
state ,
2024-06-17 04:27:08 +02:00
coordinate : new UIEventSource ( { lon , lat } )
2023-10-15 10:55:56 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2023-04-06 01:33:08 +02:00
} ,
2023-03-28 05:13:48 +02:00
new CloseNoteButton ( ) ,
2022-10-28 04:33:05 +02:00
new PlantNetDetectionViz ( ) ,
2023-03-28 05:13:48 +02:00
new TagApplyButton ( ) ,
2023-06-01 02:52:21 +02:00
new PointImportButtonViz ( ) ,
2023-05-30 02:52:22 +02:00
new WayImportButtonViz ( ) ,
2023-06-01 02:52:21 +02:00
new ConflateImportButtonViz ( ) ,
2023-03-28 05:13:48 +02:00
2022-10-28 04:33:05 +02:00
new NearbyImageVis ( ) ,
2023-03-28 05:13:48 +02:00
2021-12-12 02:59:24 +01:00
{
funcName : "wikipedia" ,
2023-04-21 16:02:36 +02:00
docs : "A box showing the corresponding wikipedia article(s) - based on the **wikidata** tag." ,
2021-12-12 02:59:24 +01:00
args : [
2021-06-23 02:15:28 +02:00
{
2021-12-12 02:59:24 +01:00
name : "keyToShowWikipediaFor" ,
2022-05-01 20:56:16 +02:00
doc : "Use the wikidata entry from this key to show the wikipedia article for. Multiple keys can be given (separated by ';'), in which case the first matching value is used" ,
2024-06-17 04:27:08 +02:00
defaultValue : "wikidata;wikipedia"
}
2021-12-12 02:59:24 +01:00
] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ . . . Wikidata . neededUrls , . . . Wikipedia . neededUrls ] ,
2023-12-31 20:57:45 +01:00
2021-12-12 02:59:24 +01:00
example :
"`{wikipedia()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the wikipedia page of whom the feature was named after. Also remember that these can be styled, e.g. `{wikipedia():max-height: 10rem}` to limit the height" ,
2023-05-06 01:23:55 +02:00
constr : ( _ , tagsSource , args ) = > {
2022-05-01 20:56:16 +02:00
const keys = args [ 0 ] . split ( ";" ) . map ( ( k ) = > k . trim ( ) )
2023-04-21 16:02:36 +02:00
const wikiIds : Store < string [ ] > = tagsSource . map ( ( tags ) = > {
const key = keys . find ( ( k ) = > tags [ k ] !== undefined && tags [ k ] !== "" )
2023-09-20 01:47:32 +02:00
return tags [ key ] ? . split ( ";" ) ? . map ( ( id ) = > id . trim ( ) ) ? ? [ ]
2023-04-21 16:02:36 +02:00
} )
return new SvelteUIElement ( WikipediaPanel , {
2024-06-17 04:27:08 +02:00
wikiIds
2023-04-21 16:02:36 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-04-22 01:45:54 +02:00
{
funcName : "wikidata_label" ,
docs : "Shows the label of the corresponding wikidata-item" ,
args : [
{
name : "keyToShowWikidataFor" ,
doc : "Use the wikidata entry from this key to show the label" ,
2024-06-17 04:27:08 +02:00
defaultValue : "wikidata"
}
2022-04-22 01:45:54 +02:00
] ,
2023-09-27 22:21:35 +02:00
needsUrls : Wikidata.neededUrls ,
2022-04-22 01:45:54 +02:00
example :
"`{wikidata_label()}` is a basic example, `{wikipedia(name:etymology:wikidata)}` to show the label itself" ,
constr : ( _ , tagsSource , args ) = >
new VariableUiElement (
tagsSource
. map ( ( tags ) = > tags [ args [ 0 ] ] )
. map ( ( wikidata ) = > {
wikidata = Utils . NoEmpty (
2024-04-05 17:49:31 +02:00
wikidata ? . split ( ";" ) ? . map ( ( wd ) = > wd . trim ( ) ) ? ? [ ]
2022-04-22 01:45:54 +02:00
) [ 0 ]
const entry = Wikidata . LoadWikidataEntry ( wikidata )
return new VariableUiElement (
entry . map ( ( e ) = > {
if ( e === undefined || e [ "success" ] === undefined ) {
return wikidata
}
const response = < WikidataResponse > e [ "success" ]
return Translation . fromMap ( response . labels )
2024-04-05 17:49:31 +02:00
} )
2022-09-08 21:40:48 +02:00
)
2024-04-05 17:49:31 +02:00
} )
2024-06-17 04:27:08 +02:00
)
2022-04-22 01:45:54 +02:00
} ,
2023-03-28 05:13:48 +02:00
new MapillaryLinkVis ( ) ,
new LanguageElement ( ) ,
{
funcName : "all_tags" ,
docs : "Prints all key-value pairs of the object - used for debugging" ,
args : [ ] ,
2024-01-22 03:42:00 +01:00
constr : (
state ,
tags : UIEventSource < Record < string , string > > ,
_ ,
__ ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-06-17 04:27:08 +02:00
) = > new SvelteUIElement ( AllTagsPanel , { tags , layer } )
2023-03-28 05:13:48 +02:00
} ,
{
funcName : "image_carousel" ,
docs : "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)" ,
args : [
{
name : "image_key" ,
defaultValue : AllImageProviders.defaultKeys.join ( "," ) ,
2024-06-17 04:27:08 +02:00
doc : "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... Multiple values are allowed if ';'-separated "
}
2023-03-28 05:13:48 +02:00
] ,
2023-09-27 22:21:35 +02:00
needsUrls : AllImageProviders.apiUrls ,
2024-04-12 15:33:15 +02:00
constr : ( state , tags , args ) = > {
2023-03-28 05:13:48 +02:00
let imagePrefixes : string [ ] = undefined
if ( args . length > 0 ) {
imagePrefixes = [ ] . concat ( . . . args . map ( ( a ) = > a . split ( "," ) ) )
}
return new ImageCarousel (
AllImageProviders . LoadImagesFor ( tags , imagePrefixes ) ,
tags ,
2024-04-05 17:49:31 +02:00
state
2023-03-28 05:13:48 +02:00
)
2024-06-17 04:27:08 +02:00
}
2023-03-28 05:13:48 +02:00
} ,
{
funcName : "image_upload" ,
docs : "Creates a button where a user can upload an image to IMGUR" ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Imgur . apiUrl ] ,
2023-03-28 05:13:48 +02:00
args : [
{
name : "image-key" ,
doc : "Image tag to add the URL to (or image-tag:0, image-tag:1 when multiple images are added)" ,
2024-06-17 04:27:08 +02:00
required : false
2023-03-28 05:13:48 +02:00
} ,
{
name : "label" ,
doc : "The text to show on the button" ,
2024-06-17 04:27:08 +02:00
required : false
}
2023-03-28 05:13:48 +02:00
] ,
constr : ( state , tags , args ) = > {
2023-10-22 23:46:58 +02:00
const targetKey = args [ 0 ] === "" ? undefined : args [ 0 ]
2023-09-25 02:13:24 +02:00
return new SvelteUIElement ( UploadImage , {
2023-09-28 23:50:27 +02:00
state ,
tags ,
2023-10-22 23:46:58 +02:00
targetKey ,
2023-09-28 23:50:27 +02:00
labelText : args [ 1 ] ,
2024-06-17 04:27:08 +02:00
image : args [ 2 ]
2023-09-25 02:13:24 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2023-03-28 05:13:48 +02:00
} ,
2021-12-12 02:59:24 +01:00
{
2023-09-28 04:02:42 +02:00
funcName : "rating" ,
2024-05-24 15:04:34 +02:00
docs : "Shows stars which represent the average rating on mangrove." ,
2023-09-29 00:28:14 +02:00
needsUrls : [ MangroveReviews . ORIGINAL_API ] ,
2023-09-28 04:02:42 +02:00
args : [
{
name : "subjectKey" ,
defaultValue : "name" ,
2024-06-17 04:27:08 +02:00
doc : "The key to use to determine the subject. If the value is specified, the subject will be <b>tags[subjectKey]</b> and will use this to filter the reviews."
2023-09-28 04:02:42 +02:00
} ,
{
name : "fallback" ,
2024-06-17 04:27:08 +02:00
doc : "The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value"
}
2023-09-28 04:02:42 +02:00
] ,
2024-04-12 15:33:15 +02:00
constr : ( state , tags , args , feature ) = > {
2023-09-28 04:02:42 +02:00
const nameKey = args [ 0 ] ? ? "name"
2024-04-12 15:33:15 +02:00
const fallbackName = args [ 1 ]
2023-09-28 04:02:42 +02:00
const reviews = FeatureReviews . construct (
2023-09-28 23:50:27 +02:00
feature ,
tags ,
state . userRelatedState . mangroveIdentity ,
{
nameKey : nameKey ,
2024-06-17 04:27:08 +02:00
fallbackName
2024-02-26 02:24:46 +01:00
} ,
2024-04-05 17:49:31 +02:00
state . featureSwitchIsTesting
2023-09-28 04:02:42 +02:00
)
2023-09-28 23:50:27 +02:00
return new SvelteUIElement ( StarsBarIcon , {
2024-06-17 04:27:08 +02:00
score : reviews.average
2023-09-28 23:50:27 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2023-09-28 04:02:42 +02:00
} ,
{
funcName : "create_review" ,
docs : "Invites the contributor to leave a review. Somewhat small UI-element until interacted" ,
2023-09-29 00:28:14 +02:00
needsUrls : [ MangroveReviews . ORIGINAL_API ] ,
2023-09-28 04:02:42 +02:00
args : [
{
name : "subjectKey" ,
defaultValue : "name" ,
2024-06-17 04:27:08 +02:00
doc : "The key to use to determine the subject. If specified, the subject will be <b>tags[subjectKey]</b>"
2023-09-28 04:02:42 +02:00
} ,
{
name : "fallback" ,
2024-06-17 04:27:08 +02:00
doc : "The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value"
}
2023-09-28 04:02:42 +02:00
] ,
constr : ( state , tags , args , feature , layer ) = > {
const nameKey = args [ 0 ] ? ? "name"
2024-04-12 15:33:15 +02:00
const fallbackName = args [ 1 ]
2023-09-28 04:02:42 +02:00
const reviews = FeatureReviews . construct (
2023-09-28 23:50:27 +02:00
feature ,
tags ,
2023-10-25 00:03:51 +02:00
state . userRelatedState ? . mangroveIdentity ,
2023-09-28 23:50:27 +02:00
{
nameKey : nameKey ,
2024-06-17 04:27:08 +02:00
fallbackName
2024-02-26 02:24:46 +01:00
} ,
2024-04-02 13:32:19 +02:00
state . featureSwitchIsTesting
2023-09-28 04:02:42 +02:00
)
2023-09-28 23:50:27 +02:00
return new SvelteUIElement ( ReviewForm , { reviews , state , tags , feature , layer } )
2024-06-17 04:27:08 +02:00
}
2023-03-28 05:13:48 +02:00
} ,
2021-12-12 02:59:24 +01:00
{
2023-09-28 04:02:42 +02:00
funcName : "list_reviews" ,
2021-12-12 02:59:24 +01:00
docs : "Adds an overview of the mangrove-reviews of this object. Mangrove.Reviews needs - in order to identify the reviewed object - a coordinate and a name. By default, the name of the object is given, but this can be overwritten" ,
2023-09-27 22:21:35 +02:00
needsUrls : [ MangroveReviews . ORIGINAL_API ] ,
2021-12-12 02:59:24 +01:00
example :
"`{reviews()}` for a vanilla review, `{reviews(name, play_forest)}` to review a play forest. If a name is known, the name will be used as identifier, otherwise 'play_forest' is used" ,
args : [
{
name : "subjectKey" ,
defaultValue : "name" ,
2024-06-17 04:27:08 +02:00
doc : "The key to use to determine the subject. If specified, the subject will be <b>tags[subjectKey]</b>"
2021-12-12 02:59:24 +01:00
} ,
{
name : "fallback" ,
2024-06-17 04:27:08 +02:00
doc : "The identifier to use, if <i>tags[subjectKey]</i> as specified above is not available. This is effectively a fallback value"
}
2021-12-12 02:59:24 +01:00
] ,
2023-09-28 04:02:42 +02:00
constr : ( state , tags , args , feature , layer ) = > {
2023-01-21 23:58:14 +01:00
const nameKey = args [ 0 ] ? ? "name"
2024-04-12 15:33:15 +02:00
const fallbackName = args [ 1 ]
2023-09-28 04:02:42 +02:00
const reviews = FeatureReviews . construct (
2023-03-28 05:13:48 +02:00
feature ,
tags ,
2023-10-25 00:03:51 +02:00
state . userRelatedState ? . mangroveIdentity ,
2023-03-28 05:13:48 +02:00
{
nameKey : nameKey ,
2024-06-17 04:27:08 +02:00
fallbackName
2024-02-26 02:24:46 +01:00
} ,
2024-04-02 13:32:19 +02:00
state . featureSwitchIsTesting
2023-03-28 05:13:48 +02:00
)
2023-09-28 23:50:27 +02:00
return new SvelteUIElement ( AllReviews , { reviews , state , tags , feature , layer } )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2024-02-20 16:53:26 +01:00
{
funcName : "import_mangrove_key" ,
docs : "Only makes sense in the usersettings. Allows to import a mangrove public key and to use this to make reviews" ,
2024-02-22 18:58:34 +01:00
args : [
{
name : "text" ,
2024-06-17 04:27:08 +02:00
doc : "The text that is shown on the button"
}
2024-02-22 18:58:34 +01:00
] ,
2024-02-20 16:53:26 +01:00
needsUrls : [ ] ,
2024-02-22 18:58:34 +01:00
constr (
state : SpecialVisualizationState ,
2024-04-12 15:33:15 +02:00
_ : UIEventSource < Record < string , string > > ,
argument : string [ ]
2024-02-22 18:58:34 +01:00
) : BaseUIElement {
2024-02-20 16:53:26 +01:00
const [ text ] = argument
return new SvelteUIElement ( ImportReviewIdentity , { state , text } )
2024-06-17 04:27:08 +02:00
}
2024-02-20 16:53:26 +01:00
} ,
2021-12-12 02:59:24 +01:00
{
funcName : "opening_hours_table" ,
docs : "Creates an opening-hours table. Usage: {opening_hours_table(opening_hours)} to create a table of the tag 'opening_hours'." ,
args : [
{
2021-06-20 03:09:55 +02:00
name : "key" ,
2021-12-12 02:59:24 +01:00
defaultValue : "opening_hours" ,
2024-06-17 04:27:08 +02:00
doc : "The tagkey from which the table is constructed."
2021-12-12 02:59:24 +01:00
} ,
{
name : "prefix" ,
defaultValue : "" ,
2024-06-17 04:27:08 +02:00
doc : "Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__"
2021-12-12 02:59:24 +01:00
} ,
{
name : "postfix" ,
defaultValue : "" ,
2024-06-17 04:27:08 +02:00
doc : "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__"
}
2021-12-12 02:59:24 +01:00
] ,
2024-02-20 11:53:13 +01:00
needsUrls : [ Constants . countryCoderEndpoint ] ,
2021-12-12 02:59:24 +01:00
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)}`" ,
2022-01-19 20:34:04 +01:00
constr : ( state , tagSource : UIEventSource < any > , args ) = > {
2023-12-15 18:14:21 +01:00
const [ key , prefix , postfix ] = args
return new OpeningHoursVisualization ( tagSource , state , key , prefix , postfix )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2023-12-04 03:32:25 +01:00
{
funcName : "opening_hours_state" ,
docs : "A small element, showing if the POI is currently open and when the next change is" ,
args : [
{
name : "key" ,
defaultValue : "opening_hours" ,
2024-06-17 04:27:08 +02:00
doc : "The tagkey from which the opening hours are read."
2023-12-04 03:32:25 +01:00
} ,
{
name : "prefix" ,
defaultValue : "" ,
2024-06-17 04:27:08 +02:00
doc : "Remove this string from the start of the value before parsing. __Note: use `&LPARENs` to indicate `(` if needed__"
2023-12-04 03:32:25 +01:00
} ,
{
name : "postfix" ,
defaultValue : "" ,
2024-06-17 04:27:08 +02:00
doc : "Remove this string from the end of the value before parsing. __Note: use `&RPARENs` to indicate `)` if needed__"
}
2023-12-04 03:32:25 +01:00
] ,
constr (
state : SpecialVisualizationState ,
tags : UIEventSource < Record < string , string > > ,
2024-04-12 15:33:15 +02:00
args : string [ ]
2023-12-31 20:57:45 +01:00
) : SvelteUIElement {
2023-12-04 03:32:25 +01:00
const keyToUse = args [ 0 ]
const prefix = args [ 1 ]
const postfix = args [ 2 ]
return new SvelteUIElement ( NextChangeViz , {
state ,
keyToUse ,
tags ,
prefix ,
2024-06-17 04:27:08 +02:00
postfix
2023-12-04 03:32:25 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2023-12-04 03:32:25 +01:00
} ,
2021-12-12 02:59:24 +01:00
{
funcName : "canonical" ,
2023-12-31 20:57:45 +01:00
2022-07-26 12:05:34 +02:00
docs : "Converts a short, canonical value into the long, translated text including the unit. This only works if a `unit` is defined for the corresponding value. The unit specification will be included in the text. " ,
example :
"If the object has `length=42`, then `{canonical(length)}` will be shown as **42 meter** (in english), **42 metre** (in french), ..." ,
2021-12-12 02:59:24 +01:00
args : [
{
name : "key" ,
2022-03-29 00:20:10 +02:00
doc : "The key of the tag to give the canonical text for" ,
2024-06-17 04:27:08 +02:00
required : true
}
2021-12-12 02:59:24 +01:00
] ,
constr : ( state , tagSource , args ) = > {
const key = args [ 0 ]
return new VariableUiElement (
tagSource
. map ( ( tags ) = > tags [ key ] )
. map ( ( value ) = > {
if ( value === undefined ) {
return undefined
}
2023-12-12 03:46:51 +01:00
const allUnits : Unit [ ] = [ ] . concat (
2024-04-05 17:49:31 +02:00
. . . ( state ? . layout ? . layers ? . map ( ( lyr ) = > lyr . units ) ? ? [ ] )
2022-09-08 21:40:48 +02:00
)
2021-12-12 02:59:24 +01:00
const unit = allUnits . filter ( ( unit ) = >
2024-04-05 17:49:31 +02:00
unit . isApplicableToKey ( key )
2021-12-12 02:59:24 +01:00
) [ 0 ]
if ( unit === undefined ) {
return value
}
2023-12-12 03:46:51 +01:00
const getCountry = ( ) = > tagSource . data . _country
2024-02-12 14:48:05 +01:00
return unit . asHumanLongValue ( value , getCountry )
2024-04-05 17:49:31 +02:00
} )
2021-12-12 02:59:24 +01:00
)
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2021-12-23 21:28:41 +01:00
{
funcName : "export_as_geojson" ,
docs : "Exports the selected feature as GeoJson-file" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-04-20 18:58:31 +02:00
constr : ( state , tagSource , tagsSource , feature , layer ) = > {
2021-12-23 21:28:41 +01:00
const t = Translations . t . general . download
2022-09-08 21:40:48 +02:00
2021-12-23 21:28:41 +01:00
return new SubtleButton (
2024-06-16 19:00:43 +02:00
new SvelteUIElement ( ArrowDownTray ) ,
2021-12-23 21:28:41 +01:00
new Combine ( [
t . downloadFeatureAsGeojson . SetClass ( "font-bold text-lg" ) ,
2024-06-17 04:27:08 +02:00
t . downloadGeoJsonHelper . SetClass ( "subtle" )
2024-04-05 17:49:31 +02:00
] ) . SetClass ( "flex flex-col" )
2023-11-30 00:39:55 +01:00
)
. onClick ( ( ) = > {
console . log ( "Exporting as Geojson" )
const tags = tagSource . data
const title =
layer ? . title ? . GetRenderValue ( tags ) ? . Subs ( tags ) ? . txt ? ? "geojson"
const data = JSON . stringify ( feature , null , " " )
Utils . offerContentsAsDownloadableFile (
data ,
title + "_mapcomplete_export.geojson" ,
{
2024-06-17 04:27:08 +02:00
mimetype : "application/vnd.geo+json"
2024-04-05 17:49:31 +02:00
}
2023-11-30 00:39:55 +01:00
)
} )
. SetClass ( "w-full" )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2021-12-23 21:28:41 +01:00
{
funcName : "open_in_iD" ,
docs : "Opens the current view in the iD-editor" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2022-01-08 04:22:50 +01:00
constr : ( state , feature ) = > {
2023-06-14 20:39:36 +02:00
return new SvelteUIElement ( OpenIdEditor , {
mapProperties : state.mapProperties ,
2024-06-17 04:27:08 +02:00
objectId : feature.data.id
2023-06-14 20:39:36 +02:00
} )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-06-08 12:53:04 +02:00
{
funcName : "open_in_josm" ,
docs : "Opens the current view in the JOSM-editor" ,
args : [ ] ,
2023-11-19 04:38:34 +01:00
needsUrls : [ "http://127.0.0.1:8111/load_and_zoom" ] ,
2023-09-27 22:21:35 +02:00
2023-03-28 05:13:48 +02:00
constr : ( state ) = > {
2023-11-19 04:38:34 +01:00
return new SvelteUIElement ( OpenJosm , { state } )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2021-12-12 02:59:24 +01:00
{
funcName : "clear_location_history" ,
docs : "A button to remove the travelled track information from the device" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2021-12-12 02:59:24 +01:00
constr : ( state ) = > {
return new SubtleButton (
2024-06-16 19:00:43 +02:00
new SvelteUIElement ( Trash ) . SetClass ( "h-6" ) ,
2024-04-05 17:49:31 +02:00
Translations . t . general . removeLocationHistory
2021-12-12 02:59:24 +01:00
) . onClick ( ( ) = > {
state . historicalUserLocations . features . setData ( [ ] )
2023-06-07 02:42:49 +02:00
state . selectedElement . setData ( undefined )
2021-12-12 02:59:24 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-01-08 14:08:04 +01:00
{
2022-01-08 04:22:50 +01:00
funcName : "visualize_note_comments" ,
2022-01-12 02:31:51 +01:00
docs : "Visualises the comments for notes" ,
2022-09-08 21:40:48 +02:00
args : [
{
2022-01-08 04:22:50 +01:00
name : "commentsKey" ,
doc : "The property name of the comments, which should be stringified json" ,
2024-06-17 04:27:08 +02:00
defaultValue : "comments"
2022-09-08 21:40:48 +02:00
} ,
{
2022-01-12 02:31:51 +01:00
name : "start" ,
2022-01-26 21:40:38 +01:00
doc : "Drop the first 'start' comments" ,
2024-06-17 04:27:08 +02:00
defaultValue : "0"
}
2022-09-08 21:40:48 +02:00
] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Constants . osmAuthConfig . url ] ,
2022-01-08 14:08:04 +01:00
constr : ( state , tags , args ) = >
new VariableUiElement (
2022-09-08 21:40:48 +02:00
tags
2022-07-27 23:59:04 +02:00
. map ( ( tags ) = > tags [ args [ 0 ] ] )
2022-01-08 04:22:50 +01:00
. map ( ( commentsStr ) = > {
2022-01-08 14:08:04 +01:00
const comments : any [ ] = JSON . parse ( commentsStr )
2022-01-12 02:31:51 +01:00
const startLoc = Number ( args [ 1 ] ? ? 0 )
2022-01-26 21:40:38 +01:00
if ( ! isNaN ( startLoc ) && startLoc > 0 ) {
2022-01-12 02:31:51 +01:00
comments . splice ( 0 , startLoc )
2022-09-08 21:40:48 +02:00
}
2022-07-29 20:04:36 +02:00
return new Combine (
2022-09-08 21:40:48 +02:00
comments
2022-01-08 04:22:50 +01:00
. filter ( ( c ) = > c . text !== "" )
2023-12-26 22:30:27 +01:00
. map (
( c , i ) = >
2024-04-05 17:49:31 +02:00
new NoteCommentElement ( c , state , i , comments . length )
)
2022-01-08 17:44:23 +01:00
) . SetClass ( "flex flex-col" )
2024-04-05 17:49:31 +02:00
} )
2024-06-17 04:27:08 +02:00
)
2022-09-08 21:40:48 +02:00
} ,
{
2022-01-08 14:08:04 +01:00
funcName : "add_image_to_note" ,
docs : "Adds an image to a node" ,
args : [
{
name : "Id-key" ,
doc : "The property name where the ID of the note to close can be found" ,
2024-06-17 04:27:08 +02:00
defaultValue : "id"
}
2022-01-08 14:08:04 +01:00
] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Imgur . apiUrl ] ,
2023-12-31 20:57:45 +01:00
2022-01-08 14:08:04 +01:00
constr : ( state , tags , args ) = > {
2022-01-26 21:40:38 +01:00
const id = tags . data [ args [ 0 ] ? ? "id" ]
2023-09-25 02:55:43 +02:00
tags = state . featureProperties . getStore ( id )
console . log ( "Id is" , id )
2023-09-28 23:50:27 +02:00
return new SvelteUIElement ( UploadImage , { state , tags } )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-02-16 02:24:15 +01:00
{
2022-03-10 23:20:50 +01:00
funcName : "title" ,
2022-02-16 02:24:15 +01:00
args : [ ] ,
2023-12-31 20:57:45 +01:00
2022-03-10 23:20:50 +01:00
docs : "Shows the title of the popup. Useful for some cases, e.g. 'What is phone number of {title()}?'" ,
example :
"`What is the phone number of {title()}`, which might automatically become `What is the phone number of XYZ`." ,
2024-01-25 03:13:18 +01:00
constr : (
state : SpecialVisualizationState ,
tagsSource : UIEventSource < Record < string , string > > ,
_ : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-01-25 03:13:18 +01:00
) = >
2022-02-20 00:30:28 +01:00
new VariableUiElement (
tagsSource . map ( ( tags ) = > {
2023-10-17 00:32:54 +02:00
if ( state . layout === undefined ) {
return "<feature title>"
}
2022-02-16 02:24:15 +01:00
const title = layer ? . title ? . GetRenderValue ( tags )
2022-03-10 23:20:50 +01:00
if ( title === undefined ) {
2022-02-20 00:30:28 +01:00
return undefined
}
2024-01-25 03:13:18 +01:00
return new SvelteUIElement ( SpecialTranslation , {
2024-01-29 17:51:12 +01:00
t : title ,
2024-01-25 03:13:18 +01:00
tags : tagsSource ,
state ,
feature ,
2024-06-17 04:27:08 +02:00
layer
2024-04-13 02:40:21 +02:00
} )
. SetClass ( "px-1" )
. setSpan ( )
2024-04-05 17:49:31 +02:00
} )
2024-06-17 04:27:08 +02:00
)
2022-05-06 12:41:24 +02:00
} ,
2022-07-13 16:12:25 +02:00
{
funcName : "maproulette_task" ,
args : [ ] ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Maproulette . defaultEndpoint ] ,
2023-03-28 05:13:48 +02:00
constr ( state , tagSource ) {
2024-04-12 15:33:15 +02:00
const parentId = tagSource . data . mr_challengeId
2023-02-12 22:58:21 +01:00
if ( parentId === undefined ) {
console . warn ( "Element " , tagSource . data . id , " has no mr_challengeId" )
return undefined
}
2024-04-12 15:33:15 +02:00
const challenge = Stores . FromPromise (
2024-05-13 18:45:43 +02:00
Utils . downloadJsonCached < MaprouletteTask > (
2023-10-05 22:43:26 +02:00
` ${ Maproulette . defaultEndpoint } /challenge/ ${ parentId } ` ,
2024-04-05 17:49:31 +02:00
24 * 60 * 60 * 1000
)
2022-09-08 21:40:48 +02:00
)
2022-07-13 16:12:25 +02:00
2022-10-28 04:33:05 +02:00
return new VariableUiElement (
2022-07-27 23:59:04 +02:00
challenge . map ( ( challenge ) = > {
2024-04-12 15:33:15 +02:00
const listItems : BaseUIElement [ ] = [ ]
2022-07-13 16:12:25 +02:00
let title : BaseUIElement
2022-07-27 23:59:04 +02:00
2022-07-13 16:12:25 +02:00
if ( challenge ? . name ) {
title = new Title ( challenge . name )
}
if ( challenge ? . description ) {
listItems . push ( new FixedUiElement ( challenge . description ) )
}
if ( challenge ? . instruction ) {
listItems . push ( new FixedUiElement ( challenge . instruction ) )
}
2022-07-27 23:59:04 +02:00
if ( listItems . length === 0 ) {
2022-07-13 16:12:25 +02:00
return undefined
} else {
return [ title , new List ( listItems ) ]
}
2024-04-05 17:49:31 +02:00
} )
2022-09-08 21:40:48 +02:00
)
2022-07-27 09:28:42 +02:00
} ,
2024-06-17 04:27:08 +02:00
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."
2022-09-08 21:40:48 +02:00
} ,
2023-02-14 00:09:04 +01:00
{
funcName : "maproulette_set_status" ,
docs : "Change the status of the given MapRoulette task" ,
2023-09-27 22:21:35 +02:00
needsUrls : [ Maproulette . defaultEndpoint ] ,
2023-06-09 16:13:35 +02:00
example :
" The following example sets the status to '2' (false positive)\n" +
"\n" +
"```json\n" +
"{\n" +
2024-06-17 04:27:08 +02:00
" \"id\": \"mark_duplicate\",\n" +
" \"render\": {\n" +
" \"special\": {\n" +
" \"type\": \"maproulette_set_status\",\n" +
" \"message\": {\n" +
" \"en\": \"Mark as not found or false positive\"\n" +
2023-06-09 16:13:35 +02:00
" },\n" +
2024-06-17 04:27:08 +02:00
" \"status\": \"2\",\n" +
" \"image\": \"close\"\n" +
2023-06-09 16:13:35 +02:00
" }\n" +
" }\n" +
"}\n" +
"```" ,
2023-02-14 00:09:04 +01:00
args : [
{
name : "message" ,
2024-06-17 04:27:08 +02:00
doc : "A message to show to the user"
2023-02-14 00:09:04 +01:00
} ,
{
name : "image" ,
doc : "Image to show" ,
2024-06-17 04:27:08 +02:00
defaultValue : "confirm"
2023-02-14 00:09:04 +01:00
} ,
{
name : "message_confirm" ,
2024-06-17 04:27:08 +02:00
doc : "What to show when the task is closed, either by the user or was already closed."
2023-02-14 00:09:04 +01:00
} ,
{
name : "status" ,
doc : "A statuscode to apply when the button is clicked. 1 = `close`, 2 = `false_positive`, 3 = `skip`, 4 = `deleted`, 5 = `already fixed` (on the map, e.g. for duplicates), 6 = `too hard`" ,
2024-06-17 04:27:08 +02:00
defaultValue : "1"
2023-02-14 00:09:04 +01:00
} ,
{
name : "maproulette_id" ,
doc : "The property name containing the maproulette id" ,
2024-06-17 04:27:08 +02:00
defaultValue : "mr_taskId"
2023-02-14 00:09:04 +01:00
} ,
2024-02-14 12:20:29 +01:00
{
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" ,
2024-06-17 04:27:08 +02:00
defaultValue : ""
}
2023-02-14 00:09:04 +01:00
] ,
2023-12-31 20:57:45 +01:00
2023-03-29 17:21:20 +02:00
constr : ( state , tagsSource , args ) = > {
2024-02-20 11:53:13 +01:00
let [
message ,
image ,
message_closed ,
statusToSet ,
maproulette_id_key ,
2024-06-17 04:27:08 +02:00
askFeedback
2024-02-20 11:53:13 +01:00
] = args
2023-02-14 00:09:04 +01:00
if ( image === "" ) {
image = "confirm"
}
2023-06-14 20:39:36 +02:00
if ( maproulette_id_key === "" || maproulette_id_key === undefined ) {
2023-06-09 16:13:35 +02:00
maproulette_id_key = "mr_taskId"
}
2024-02-02 16:38:58 +01:00
statusToSet = statusToSet ? ? "1"
2023-12-09 16:52:15 +01:00
return new SvelteUIElement ( MaprouletteSetStatus , {
state ,
tags : tagsSource ,
message ,
image ,
message_closed ,
statusToSet ,
maproulette_id_key ,
2024-06-17 04:27:08 +02:00
askFeedback
2023-12-09 16:52:15 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2023-02-14 00:09:04 +01:00
} ,
2022-07-25 18:55:15 +02:00
{
funcName : "statistics" ,
docs : "Show general statistics about the elements currently in view. Intended to use on the `current_view`-layer" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-03-29 17:21:20 +02:00
constr : ( state ) = > {
2023-03-28 05:13:48 +02:00
return new Combine (
state . layout . layers
2024-04-13 02:40:21 +02:00
. filter (
( l ) = >
l . name !== null &&
l . title &&
state . perLayer . get ( l . id ) !== undefined
)
2023-03-28 05:13:48 +02:00
. map (
( l ) = > {
const fs = state . perLayer . get ( l . id )
2024-03-28 03:39:46 +01:00
console . log ( ">>>" , l . id , fs )
2023-04-27 00:58:21 +02:00
const bbox = state . mapProperties . bounds
2023-03-28 05:13:48 +02:00
const fsBboxed = new BBoxFeatureSourceForLayer ( fs , bbox )
return new StatisticsPanel ( fsBboxed )
} ,
2024-04-05 17:49:31 +02:00
[ state . mapProperties . bounds ]
)
2023-03-28 05:13:48 +02:00
)
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-07-27 23:59:04 +02:00
{
funcName : "send_email" ,
docs : "Creates a `mailto`-link where some fields are already set and correctly escaped. The user will be promted to send the email" ,
args : [
2022-09-08 21:40:48 +02:00
{
2022-07-27 23:59:04 +02:00
name : "to" ,
doc : "Who to send the email to?" ,
2024-06-17 04:27:08 +02:00
required : true
2022-09-08 21:40:48 +02:00
} ,
{
2022-07-27 23:59:04 +02:00
name : "subject" ,
doc : "The subject of the email" ,
2024-06-17 04:27:08 +02:00
required : true
2022-09-08 21:40:48 +02:00
} ,
{
2022-07-27 23:59:04 +02:00
name : "body" ,
doc : "The text in the email" ,
2024-06-17 04:27:08 +02:00
required : true
2022-09-08 21:40:48 +02:00
} ,
2022-07-27 23:59:04 +02:00
2022-09-08 21:40:48 +02:00
{
2022-07-27 23:59:04 +02:00
name : "button_text" ,
doc : "The text shown on the button in the UI" ,
2024-06-17 04:27:08 +02:00
required : true
}
2022-09-08 21:40:48 +02:00
] ,
2023-09-27 22:21:35 +02:00
2023-03-28 05:13:48 +02:00
constr ( __ , tags , args ) {
2023-09-15 01:53:50 +02:00
return new SvelteUIElement ( SendEmail , { args , tags } )
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2022-07-28 09:16:19 +02:00
{
2023-04-07 02:13:57 +02:00
funcName : "link" ,
2023-09-02 00:55:07 +02:00
docs : "Construct a link. By using the 'special' visualisation notation, translations should be easier" ,
2023-04-07 02:13:57 +02:00
args : [
{
name : "text" ,
doc : "Text to be shown" ,
2024-06-17 04:27:08 +02:00
required : true
2023-04-07 02:13:57 +02:00
} ,
{
name : "href" ,
2024-02-13 00:52:00 +01:00
doc : "The URL to link to. Note that this will be URI-encoded before " ,
2024-06-17 04:27:08 +02:00
required : true
2023-04-07 02:13:57 +02:00
} ,
2023-04-15 02:28:24 +02:00
{
name : "class" ,
2024-06-17 04:27:08 +02:00
doc : "CSS-classes to add to the element"
2023-04-15 02:28:24 +02:00
} ,
2023-09-21 02:31:35 +02:00
{
name : "download" ,
2024-06-17 04:27:08 +02:00
doc : "Expects a string which denotes the filename to download the contents of `href` into. If set, this link will act as a download-button."
2023-09-21 02:31:35 +02:00
} ,
2023-12-14 18:25:35 +01:00
{
name : "arialabel" ,
2024-06-17 04:27:08 +02:00
doc : "If set, this text will be used as aria-label"
}
2023-04-07 02:13:57 +02:00
] ,
2023-12-31 20:57:45 +01:00
2023-04-07 02:13:57 +02:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
2024-04-05 17:49:31 +02:00
args : string [ ]
2023-04-07 02:13:57 +02:00
) : BaseUIElement {
2023-12-19 16:45:27 +01:00
let [ text , href , classnames , download , ariaLabel ] = args
if ( download === "" ) {
download = undefined
}
2023-12-14 18:25:35 +01:00
const newTab = download === undefined && ! href . startsWith ( "#" )
2024-04-13 02:40:21 +02:00
const textStore = tagSource . map ( ( tags ) = > Utils . SubstituteKeys ( text , tags ) )
const hrefStore = tagSource . map (
( tags ) = >
Utils . SubstituteKeys ( href , tags ) . replaceAll (
/ /g ,
"%20"
) /* Chromium based browsers eat the spaces */
)
2024-04-10 15:29:48 +02:00
return new SvelteUIElement ( DynLink , {
2024-04-13 02:40:21 +02:00
text : textStore ,
2024-04-10 15:29:48 +02:00
href : hrefStore ,
classnames : new ImmutableStore ( classnames ) ,
2024-04-13 02:40:21 +02:00
download : tagSource.map ( ( tags ) = > Utils . SubstituteKeys ( download , tags ) ) ,
ariaLabel : tagSource.map ( ( tags ) = > Utils . SubstituteKeys ( ariaLabel , tags ) ) ,
2024-06-17 04:27:08 +02:00
newTab : new ImmutableStore ( newTab )
2024-04-12 15:16:33 +02:00
} ) . setSpan ( )
2024-06-17 04:27:08 +02:00
}
2023-04-07 02:13:57 +02:00
} ,
{
2022-07-28 09:16:19 +02:00
funcName : "multi" ,
docs : "Given an embedded tagRendering (read only) and a key, will read the keyname as a JSON-list. Every element of this list will be considered as tags and rendered with the tagRendering" ,
2022-07-29 20:04:36 +02:00
example :
"```json\n" +
JSON . stringify (
2022-07-28 09:16:19 +02:00
{
render : {
special : {
2022-07-29 20:04:36 +02:00
type : "multi" ,
key : "_doors_from_building_properties" ,
2023-02-09 02:45:19 +01:00
tagrendering : {
2024-06-17 04:27:08 +02:00
en : "The building containing this feature has a <a href='#{id}'>door</a> of width {entrance:width}"
}
}
}
2022-07-29 20:04:36 +02:00
} ,
2022-09-08 21:40:48 +02:00
null ,
2024-04-05 17:49:31 +02:00
" "
2022-09-08 21:40:48 +02:00
) +
2022-10-11 01:39:09 +02:00
"\n```" ,
2022-09-08 21:40:48 +02:00
args : [
2022-07-29 20:04:36 +02:00
{
2021-12-12 02:59:24 +01:00
name : "key" ,
2022-08-22 19:16:37 +02:00
doc : "The property to read and to interpret as a list of properties" ,
2024-06-17 04:27:08 +02:00
required : true
2022-09-08 21:40:48 +02:00
} ,
{
2022-07-29 20:04:36 +02:00
name : "tagrendering" ,
doc : "An entire tagRenderingConfig" ,
2024-06-17 04:27:08 +02:00
required : true
2022-07-29 20:04:36 +02:00
} ,
2024-02-02 13:37:05 +01:00
{
name : "classes" ,
2024-06-17 04:27:08 +02:00
doc : "CSS-classes to apply on every individual item. Seperated by `space`"
}
2022-09-08 21:40:48 +02:00
] ,
2024-01-25 03:13:18 +01:00
constr (
state : SpecialVisualizationState ,
featureTags : UIEventSource < Record < string , string > > ,
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-01-25 03:13:18 +01:00
) {
2024-02-02 13:37:05 +01:00
const [ key , tr , classesRaw ] = args
let classes = classesRaw ? ? ""
2023-06-14 20:39:36 +02:00
const translation = new Translation ( { "*" : tr } )
2022-07-29 20:04:36 +02:00
return new VariableUiElement (
featureTags . map ( ( tags ) = > {
2024-01-31 12:09:15 +01:00
let properties : object [ ]
2024-02-02 13:37:05 +01:00
if ( typeof tags [ key ] === "string" ) {
properties = JSON . parse ( tags [ key ] )
} else {
properties = < any > tags [ key ]
2024-01-31 12:09:15 +01:00
}
2024-04-13 02:40:21 +02:00
if ( ! properties ) {
console . debug (
"Could not create a special visualization for multi(" ,
args . join ( ", " ) + ")" ,
"no properties found for object" ,
feature . properties . id
)
2024-04-10 15:29:48 +02:00
return undefined
}
2022-07-29 20:04:36 +02:00
const elements = [ ]
for ( const property of properties ) {
2024-01-25 03:13:18 +01:00
const subsTr = new SvelteUIElement ( SpecialTranslation , {
t : translation ,
2024-01-31 12:09:15 +01:00
tags : new ImmutableStore ( property ) ,
2024-01-25 03:13:18 +01:00
state ,
feature ,
2024-06-17 04:27:08 +02:00
layer
2024-02-02 13:37:05 +01:00
} ) . SetClass ( classes )
2022-07-29 20:04:36 +02:00
elements . push ( subsTr )
}
2024-01-28 03:27:17 +01:00
return elements
2024-04-05 17:49:31 +02:00
} )
2022-09-08 21:40:48 +02:00
)
2024-06-17 04:27:08 +02:00
}
2022-09-08 21:40:48 +02:00
} ,
2023-08-08 13:52:58 +02:00
{
funcName : "translated" ,
docs : "If the given key can be interpreted as a JSON, only show the key containing the current language (or 'en'). This specialRendering is meant to be used by MapComplete studio and is not useful in map themes" ,
2023-12-31 20:57:45 +01:00
2023-08-08 13:52:58 +02:00
args : [
{
name : "key" ,
doc : "The attribute to interpret as json" ,
2024-06-17 04:27:08 +02:00
defaultValue : "value"
}
2023-08-08 13:52:58 +02:00
] ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-08-08 13:52:58 +02:00
) : BaseUIElement {
return new VariableUiElement (
tagSource . map ( ( tags ) = > {
const v = tags [ argument [ 0 ] ? ? "value" ]
try {
2023-10-17 00:32:54 +02:00
const tr = typeof v === "string" ? JSON . parse ( v ) : v
2023-08-08 13:52:58 +02:00
return new Translation ( tr ) . SetClass ( "font-bold" )
} catch ( e ) {
2023-10-24 22:01:10 +02:00
console . error ( "Cannot create a translation for" , v , "due to" , e )
2023-10-17 00:32:54 +02:00
return JSON . stringify ( v )
2023-08-08 13:52:58 +02:00
}
2024-04-05 17:49:31 +02:00
} )
2023-08-08 13:52:58 +02:00
)
2024-06-17 04:27:08 +02:00
}
2023-08-08 13:52:58 +02:00
} ,
2023-08-10 14:10:06 +02:00
{
funcName : "fediverse_link" ,
docs : "Converts a fediverse username or link into a clickable link" ,
2023-08-10 16:25:25 +02:00
args : [
{
name : "key" ,
doc : "The attribute-name containing the link" ,
2024-06-17 04:27:08 +02:00
required : true
}
2023-08-10 16:25:25 +02:00
] ,
2023-12-31 20:57:45 +01:00
2023-08-10 16:25:25 +02:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-08-10 16:25:25 +02:00
) : BaseUIElement {
2023-08-10 14:10:06 +02:00
const key = argument [ 0 ]
const validator = new FediverseValidator ( )
2023-08-10 16:25:25 +02:00
return new VariableUiElement (
tagSource
. map ( ( tags ) = > tags [ key ] )
. map ( ( fediAccount ) = > {
fediAccount = validator . reformat ( fediAccount )
const [ _ , username , host ] = fediAccount . match (
2024-04-05 17:49:31 +02:00
FediverseValidator . usernameAtServer
2023-08-10 16:25:25 +02:00
)
2024-01-21 02:54:49 +01:00
const normalLink = new SvelteUIElement ( Link , {
2023-12-14 18:25:35 +01:00
text : fediAccount ,
2024-01-21 02:54:49 +01:00
href : "https://" + host + "/@" + username ,
2024-06-17 04:27:08 +02:00
newTab : true
2023-12-14 18:25:35 +01:00
} )
2024-01-21 02:54:49 +01:00
const loggedInContributorMastodon =
state . userRelatedState ? . preferencesAsTags ? . data ? . [
"_mastodon_link"
2024-06-17 04:27:08 +02:00
]
2024-01-21 02:54:49 +01:00
console . log (
"LoggedinContributorMastodon" ,
2024-04-05 17:49:31 +02:00
loggedInContributorMastodon
2024-01-21 02:54:49 +01:00
)
if ( ! loggedInContributorMastodon ) {
return normalLink
}
const homeUrl = new URL ( loggedInContributorMastodon )
const homeHost = homeUrl . protocol + "//" + homeUrl . hostname
return new Combine ( [
normalLink ,
new SvelteUIElement ( Link , {
href : homeHost + "/" + fediAccount ,
text : Translations.t.validation.fediverse.onYourServer ,
2024-06-17 04:27:08 +02:00
newTab : true
} ) . SetClass ( "button" )
2024-01-21 02:54:49 +01:00
] )
2024-04-05 17:49:31 +02:00
} )
2023-08-10 16:25:25 +02:00
)
2024-06-17 04:27:08 +02:00
}
2023-08-10 16:25:25 +02:00
} ,
2023-10-20 19:04:55 +02:00
{
funcName : "braced" ,
docs : "Show a literal text within braces" ,
2023-12-31 20:57:45 +01:00
2023-10-20 19:04:55 +02:00
args : [
{
name : "text" ,
required : true ,
2024-06-17 04:27:08 +02:00
doc : "The value to show"
}
2023-10-20 19:04:55 +02:00
] ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-10-20 19:04:55 +02:00
) : BaseUIElement {
return new FixedUiElement ( "{" + args [ 0 ] + "}" )
2024-06-17 04:27:08 +02:00
}
2023-10-20 19:04:55 +02:00
} ,
2023-10-22 01:30:05 +02:00
{
funcName : "tags" ,
docs : "Shows a (json of) tags in a human-readable way + links to the wiki" ,
2023-12-31 20:57:45 +01:00
2023-10-22 01:30:05 +02:00
args : [
{
name : "key" ,
defaultValue : "value" ,
2024-06-17 04:27:08 +02:00
doc : "The key to look for the tags"
}
2023-10-22 01:30:05 +02:00
] ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-10-22 01:30:05 +02:00
) : BaseUIElement {
const key = argument [ 0 ] ? ? "value"
return new VariableUiElement (
tagSource . map ( ( tags ) = > {
let value = tags [ key ]
if ( ! value ) {
return new FixedUiElement ( "No tags found" ) . SetClass ( "font-bold" )
}
if ( typeof value === "string" && value . startsWith ( "{" ) ) {
value = JSON . parse ( value )
}
try {
const parsed = TagUtils . Tag ( value )
return parsed . asHumanString ( true , false , { } )
} catch ( e ) {
return new FixedUiElement (
"Could not parse this tag: " +
2024-06-17 04:27:08 +02:00
JSON . stringify ( value ) +
" due to " +
e
2023-10-22 01:30:05 +02:00
) . SetClass ( "alert" )
}
2024-04-05 17:49:31 +02:00
} )
2023-10-22 01:30:05 +02:00
)
2024-06-17 04:27:08 +02:00
}
2023-10-22 01:30:05 +02:00
} ,
2023-11-11 14:35:45 +01:00
{
funcName : "giggity" ,
args : [
{
name : "giggityUrl" ,
required : true ,
2024-06-17 04:27:08 +02:00
doc : "The URL of the giggity-XML"
}
2023-11-11 14:35:45 +01:00
] ,
docs : "Shows events that are happening based on a Giggity URL" ,
2023-11-19 16:31:58 +01:00
needsUrls : ( args ) = > args [ 0 ] ,
2023-12-31 20:57:45 +01:00
2023-11-11 14:35:45 +01:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-11-11 14:35:45 +01:00
) : BaseUIElement {
const giggityUrl = argument [ 0 ]
return new SvelteUIElement ( Giggity , { tags : tagSource , state , giggityUrl } )
2024-06-17 04:27:08 +02:00
}
2023-11-11 14:35:45 +01:00
} ,
2023-11-12 10:14:51 +01:00
{
funcName : "gps_all_tags" ,
2023-12-31 20:57:45 +01:00
2023-11-12 10:14:51 +01:00
docs : "Shows the current tags of the GPS-representing object, used for debugging" ,
args : [ ] ,
constr (
state : SpecialVisualizationState ,
_ : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-11-12 10:14:51 +01:00
) : BaseUIElement {
const tags = ( < ThemeViewState > (
state
) ) . geolocation . currentUserLocation . features . map (
2024-04-05 17:49:31 +02:00
( features ) = > features [ 0 ] ? . properties
2023-11-12 10:14:51 +01:00
)
2023-12-16 01:29:42 +01:00
return new Combine ( [
new SvelteUIElement ( OrientationDebugPanel , { } ) ,
new SvelteUIElement ( AllTagsPanel , {
state ,
2024-06-17 04:27:08 +02:00
tags
} )
2023-12-16 01:29:42 +01:00
] )
2024-06-17 04:27:08 +02:00
}
2023-11-12 10:14:51 +01:00
} ,
2023-11-22 19:39:19 +01:00
{
funcName : "favourite_status" ,
2023-12-31 20:57:45 +01:00
2023-11-22 19:39:19 +01:00
docs : "A button that allows a (logged in) contributor to mark a location as a favourite location" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-11-22 19:39:19 +01:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-11-22 19:39:19 +01:00
) : BaseUIElement {
return new SvelteUIElement ( MarkAsFavourite , {
tags : tagSource ,
state ,
layer ,
2024-06-17 04:27:08 +02:00
feature
2023-11-22 19:39:19 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2023-11-22 19:39:19 +01:00
} ,
{
funcName : "favourite_icon" ,
2023-12-31 20:57:45 +01:00
2023-11-22 19:39:19 +01:00
docs : "A small button that allows a (logged in) contributor to mark a location as a favourite location, sized to fit a title-icon" ,
args : [ ] ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-11-22 19:39:19 +01:00
) : BaseUIElement {
return new SvelteUIElement ( MarkAsFavouriteMini , {
tags : tagSource ,
state ,
layer ,
2024-06-17 04:27:08 +02:00
feature
2023-12-31 20:57:45 +01:00
} ) . SetClass ( "w-full h-full" )
2024-06-17 04:27:08 +02:00
}
2023-11-22 19:39:19 +01:00
} ,
2023-12-24 05:01:10 +01:00
{
funcName : "direction_indicator" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-12-24 05:01:10 +01:00
docs : "Gives a distance indicator and a compass pointing towards the location from your GPS-location. If clicked, centers the map on the object" ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2023-12-24 05:01:10 +01:00
) : BaseUIElement {
return new SvelteUIElement ( DirectionIndicator , { state , feature } )
2024-06-17 04:27:08 +02:00
}
2023-12-24 05:01:10 +01:00
} ,
{
funcName : "qr_code" ,
args : [ ] ,
2023-12-31 20:57:45 +01:00
2023-12-24 05:01:10 +01:00
docs : "Generates a QR-code to share the selected object" ,
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
argument : string [ ] ,
2024-05-07 00:42:52 +02:00
feature : Feature
2023-12-24 05:01:10 +01:00
) : BaseUIElement {
2024-03-19 02:07:10 +01:00
const smallSize = 100
const bigSize = 200
const size = new UIEventSource ( smallSize )
2023-12-25 19:59:58 +01:00
return new VariableUiElement (
tagSource
. map ( ( tags ) = > tags . id )
2024-04-13 02:40:21 +02:00
. map (
( id ) = > {
if ( id . startsWith ( "node/-" ) ) {
// Not yet uploaded
return undefined
}
const [ lon , lat ] = GeoOperations . centerpointCoordinates ( feature )
const includeLayout = window . location . pathname
. split ( "/" )
. at ( - 1 )
. startsWith ( "theme" )
const layout = includeLayout
? "layout=" + state . layout . id + "&"
: ""
const url =
` ${ window . location . protocol } // ${ window . location . host } ${ window . location . pathname } ? ${ layout } lat= ${ lat } &lon= ${ lon } &z=15 ` +
` # ${ id } `
return new Img ( new Qr ( url ) . toImageElement ( size . data ) ) . SetStyle (
` width: ${ size . data } px `
)
} ,
[ size ]
)
2024-04-05 17:49:31 +02:00
) . onClick ( ( ) = > {
if ( size . data !== bigSize ) {
2024-03-19 02:07:10 +01:00
size . setData ( bigSize )
2024-04-05 17:49:31 +02:00
} else {
2024-03-19 02:07:10 +01:00
size . setData ( smallSize )
}
} )
2024-06-17 04:27:08 +02:00
}
2023-12-24 05:01:10 +01:00
} ,
2023-12-31 14:09:25 +01:00
{
funcName : "direction_absolute" ,
docs : "Converts compass degrees (with 0° being north, 90° being east, ...) into a human readable, translated direction such as 'north', 'northeast'" ,
args : [
{
name : "key" ,
doc : "The attribute containing the degrees" ,
2024-06-17 04:27:08 +02:00
defaultValue : "_direction:centerpoint"
}
2023-12-31 14:09:25 +01:00
] ,
2023-12-31 20:57:45 +01:00
2023-12-31 14:09:25 +01:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
2024-05-07 00:42:52 +02:00
args : string [ ]
2023-12-31 14:09:25 +01:00
) : BaseUIElement {
const key = args [ 0 ] === "" ? "_direction:centerpoint" : args [ 0 ]
return new VariableUiElement (
tagSource
. map ( ( tags ) = > {
console . log ( "Direction value" , tags [ key ] , key )
return tags [ key ]
} )
. mapD ( ( value ) = > {
const dir = GeoOperations . bearingToHuman (
2024-04-05 17:49:31 +02:00
GeoOperations . parseBearing ( value )
2023-12-31 14:09:25 +01:00
)
console . log ( "Human dir" , dir )
return Translations . t . general . visualFeedback . directionsAbsolute [ dir ]
2024-04-05 17:49:31 +02:00
} )
2023-12-31 14:09:25 +01:00
)
2024-06-17 04:27:08 +02:00
}
2023-12-31 14:09:25 +01:00
} ,
2024-01-13 05:24:56 +01:00
{
funcName : "compare_data" ,
2024-01-14 22:24:35 +01:00
needsUrls : ( args ) = > args [ 1 ] . split ( ";" ) ,
2024-01-16 04:20:25 +01:00
args : [
2024-01-13 05:24:56 +01:00
{
name : "url" ,
required : true ,
2024-06-17 04:27:08 +02:00
doc : "The attribute containing the url where to fetch more data"
2024-01-13 05:24:56 +01:00
} ,
2024-01-14 22:24:35 +01:00
{
2024-01-16 04:20:25 +01:00
name : "host" ,
required : true ,
2024-06-17 04:27:08 +02:00
doc : "The domain name(s) where data might be fetched from - this is needed to set the CSP. A domain must include 'https', e.g. 'https://example.com'. For multiple domains, separate them with ';'. If you don't know the possible domains, use '*'. "
2024-01-14 22:24:35 +01:00
} ,
2024-01-16 04:20:25 +01:00
{
2024-01-17 18:08:14 +01:00
name : "readonly" ,
2024-01-16 04:20:25 +01:00
required : false ,
2024-06-17 04:27:08 +02:00
doc : "If 'yes', will not show 'apply'-buttons"
}
2024-01-13 05:24:56 +01:00
] ,
docs : "Gives an interactive element which shows a tag comparison between the OSM-object and the upstream object. This allows to copy some or all tags into OSM" ,
2024-01-17 18:08:14 +01:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-01-17 18:08:14 +01:00
) : BaseUIElement {
2024-01-13 05:24:56 +01:00
const url = args [ 0 ]
2024-01-16 04:20:25 +01:00
const readonly = args [ 3 ] === "yes"
2024-02-26 02:24:46 +01:00
const externalData = Stores . FromPromiseWithErr ( Utils . downloadJson ( url ) )
2024-01-16 04:20:25 +01:00
return new SvelteUIElement ( ComparisonTool , {
url ,
state ,
tags : tagSource ,
layer ,
feature ,
2024-01-17 18:08:14 +01:00
readonly ,
2024-06-17 04:27:08 +02:00
externalData
2024-01-16 04:20:25 +01:00
} )
2024-06-17 04:27:08 +02:00
}
2024-01-16 04:20:25 +01:00
} ,
2024-02-14 12:20:29 +01:00
{
funcName : "login_button" ,
2024-02-20 11:53:13 +01:00
args : [ ] ,
2024-02-14 12:20:29 +01:00
docs : "Show a login button" ,
needsUrls : [ ] ,
2024-02-20 11:53:13 +01:00
constr (
state : SpecialVisualizationState ,
tagSource : UIEventSource < Record < string , string > > ,
args : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-02-20 11:53:13 +01:00
) : BaseUIElement {
return new Toggle (
undefined ,
2024-06-16 16:06:26 +02:00
new SvelteUIElement ( LoginButton , { osmConnection : state.osmConnection } ) ,
2024-04-05 17:49:31 +02:00
state . osmConnection . isLoggedIn
2024-02-20 11:53:13 +01:00
)
2024-06-17 04:27:08 +02:00
}
2024-02-14 12:20:29 +01:00
} ,
2024-02-22 18:58:34 +01:00
{
funcName : "linked_data_from_website" ,
docs : "Attempts to load (via a proxy) the specified website and parsed ld+json from there. Suitable data will be offered to import into OSM" ,
args : [
{
name : "key" ,
defaultValue : "website" ,
2024-06-17 04:27:08 +02:00
doc : "Attempt to load ld+json from the specified URL. This can be in an embedded <script type='ld+json'>"
2024-02-22 18:58:34 +01:00
} ,
2024-04-05 17:49:31 +02:00
{
name : "useProxy" ,
defaultValue : "yes" ,
2024-06-17 04:27:08 +02:00
doc : "If 'yes', uses the provided proxy server. This proxy server will scrape HTML and search for a script with `lang='ld+json'`. If `no`, the data will be downloaded and expects a linked-data-json directly"
2024-04-05 17:49:31 +02:00
} ,
{
name : "host" ,
2024-06-17 04:27:08 +02:00
doc : "If not using a proxy, define what host the website is allowed to connect to"
2024-04-05 17:49:31 +02:00
} ,
{
name : "mode" ,
2024-06-17 04:27:08 +02:00
doc : "If `display`, only show the data in tabular and readonly form, ignoring already existing tags. This is used to explicitly show all the tags. If unset or anything else, allow to apply/import on OSM"
2024-06-18 03:33:11 +02:00
} ,
{
name : "collapsed" ,
defaultValue : "yes" ,
doc : "If the containing accordion should be closed"
2024-06-17 04:27:08 +02:00
}
2024-02-22 18:58:34 +01:00
] ,
2024-04-09 13:58:23 +02:00
needsUrls : [ Constants . linkedDataProxy , "http://www.schema.org" ] ,
2024-02-22 18:58:34 +01:00
constr (
state : SpecialVisualizationState ,
2024-02-26 02:24:46 +01:00
tags : UIEventSource < Record < string , string > > ,
2024-02-22 18:58:34 +01:00
argument : string [ ] ,
feature : Feature ,
2024-04-05 17:49:31 +02:00
layer : LayerConfig
2024-02-22 18:58:34 +01:00
) : BaseUIElement {
const key = argument [ 0 ] ? ? "website"
2024-04-05 17:49:31 +02:00
const useProxy = argument [ 1 ] !== "no"
const readonly = argument [ 3 ] === "readonly"
2024-06-18 03:33:11 +02:00
const isClosed = ( arguments [ 4 ] ? ? "yes" ) === "yes"
2024-04-05 17:49:31 +02:00
2024-04-13 02:40:21 +02:00
const url = tags
. mapD ( ( tags ) = > {
if ( ! tags . _country || ! tags [ key ] || tags [ key ] === "undefined" ) {
return null
}
return JSON . stringify ( { url : tags [ key ] , country : tags._country } )
} )
. mapD ( ( data ) = > JSON . parse ( data ) )
const sourceUrl : Store < string | undefined > = url . mapD ( ( url ) = > url . url )
2024-06-16 16:06:26 +02:00
const externalData : Store < { success : GeoJsonProperties } | { error : any } > =
url . bindD ( ( { url , country } ) = > {
if ( url . startsWith ( "https://data.velopark.be/" ) ) {
return Stores . FromPromiseWithErr (
( async ( ) = > {
try {
const loadAll =
layer . id . toLowerCase ( ) . indexOf ( "maproulette" ) >= 0 // Dirty hack
const features =
await LinkedDataLoader . fetchVeloparkEntry (
url ,
loadAll
)
const feature =
features . find (
( f ) = > f . properties [ "ref:velopark" ] === url
) ? ? features [ 0 ]
const properties = feature . properties
properties [ "ref:velopark" ] = url
console . log ( "Got properties from velopark:" , properties )
return properties
} catch ( e ) {
console . error ( e )
throw e
}
} ) ( )
)
}
2024-04-13 02:40:21 +02:00
return Stores . FromPromiseWithErr (
2024-06-16 16:06:26 +02:00
LinkedDataLoader . fetchJsonLd ( url , { country } , useProxy )
2024-04-13 02:40:21 +02:00
)
2024-06-16 16:06:26 +02:00
} )
2024-02-26 02:24:46 +01:00
2024-04-13 02:40:21 +02:00
externalData . addCallbackAndRunD ( ( lod ) = >
console . log ( "linked_data_from_website received the following data:" , lod )
)
2024-02-26 02:24:46 +01:00
return new Toggle (
new SvelteUIElement ( ComparisonTool , {
feature ,
state ,
tags ,
layer ,
externalData ,
2024-04-05 17:49:31 +02:00
sourceUrl ,
2024-06-17 04:27:08 +02:00
readonly
2024-04-13 02:40:21 +02:00
} ) ,
undefined ,
url . map ( ( url ) = > ! ! url )
2024-02-26 02:24:46 +01:00
)
2024-06-17 04:27:08 +02:00
}
2024-06-16 16:06:26 +02:00
} ,
2024-06-17 04:27:08 +02:00
{
funcName : "if_nothing_known" ,
args : [ {
name : "text" ,
doc : "Text to show" ,
required : true
} ,
{ name : "cssClasses" , doc : "Classes to apply onto the text" } ] ,
docs : "Shows a 'nothing is currently known-message if there is at least one unanswered question and no known (answerable) question" ,
constr ( state : SpecialVisualizationState , tagSource : UIEventSource < Record < string , string > > , argument : string [ ] , feature : Feature , layer : LayerConfig ) : BaseUIElement {
const text = argument [ 0 ]
const cssClasses = argument [ 1 ]
return new SvelteUIElement ( NothingKnown , { state , tags : tagSource , layer , text , cssClasses } )
}
}
2020-10-17 02:37:53 +02:00
]
2022-01-08 04:22:50 +01:00
specialVisualizations . push ( new AutoApplyButton ( specialVisualizations ) )
2022-04-22 01:45:54 +02:00
2022-11-02 13:47:34 +01:00
const invalid = specialVisualizations
2023-06-14 20:39:36 +02:00
. map ( ( sp , i ) = > ( { sp , i } ) )
2022-11-02 13:47:34 +01:00
. filter ( ( sp ) = > sp . sp . funcName === undefined )
if ( invalid . length > 0 ) {
throw (
"Invalid special visualisation found: funcName is undefined for " +
invalid . map ( ( sp ) = > sp . i ) . join ( ", " ) +
2024-06-17 04:27:08 +02:00
". Did you perhaps type \n funcName: \"funcname\" // type declaration uses COLON\ninstead of:\n funcName = \"funcName\" // value definition uses EQUAL"
2022-11-02 13:47:34 +01:00
)
2022-10-28 04:33:05 +02:00
}
2024-01-25 13:41:33 +01:00
SpecialVisualisationUtils . specialVisualizations = Utils . NoNull ( specialVisualizations )
2022-01-08 04:22:50 +01:00
return specialVisualizations
2020-10-17 02:37:53 +02:00
}
2020-10-09 20:10:21 +02:00
}