import { SpecialVisualization, SpecialVisualizationState, SpecialVisualizationSvelte } from "../SpecialVisualization" import SvelteUIElement from "../Base/SvelteUIElement" import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource" import { Feature, GeoJSON } from "geojson" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import Questionbox from "../Popup/TagRendering/Questionbox.svelte" import MinimapViz from "../Popup/MinimapViz.svelte" import SplitRoadWizard from "../Popup/SplitRoadWizard.svelte" import MoveWizard from "../Popup/MoveWizard.svelte" import DeleteWizard from "../Popup/DeleteFlow/DeleteWizard.svelte" import QrCode from "../Popup/QrCode.svelte" import NothingKnown from "../Popup/NothingKnown.svelte" import { ShareLinkViz } from "../Popup/ShareLinkViz" import { GeoOperations } from "../../Logic/GeoOperations" import AddNewPoint from "../Popup/AddNewPoint/AddNewPoint.svelte" import BaseUIElement from "../BaseUIElement" import { VariableUiElement } from "../Base/VariableUIElement" import { Translation } from "../i18n/Translation" import { FixedUiElement } from "../Base/FixedUiElement" import { default as FeatureTitle } from "../Popup/Title.svelte" import CreateCopy from "../Popup/AddNewPoint/CreateCopy.svelte" /** * Thin wrapper around QuestionBox.svelte to include it into the special Visualisations */ class QuestionViz extends SpecialVisualizationSvelte { funcName = "questions" needsUrls = [] docs = "The special element which shows the questions which are unknown. Added by default if not yet there" args = [ { name: "labels", 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", }, { name: "blacklisted-labels", doc: "One or more ';'-separated labels of questions which should _not_ be included. Note that the questionbox which is added by default will blacklist 'hidden'. If both a whitelist and a blacklist are given, will show questions having at least one label from the whitelist but none of the blacklist.", }, { name: "show_all", default: "user-preference", doc: "Either `no`, `yes` or `user-preference`. Indicates if all questions should be shown at once", }, ] group = "default" constr( state: SpecialVisualizationState, tags: UIEventSource>, args: string[], feature: Feature, layer: LayerConfig ): SvelteUIElement { const labels = args[0] ?.split(";") ?.map((s) => s.trim()) ?.filter((s) => s !== "") const blacklist = args[1] ?.split(";") ?.map((s) => s.trim()) ?.filter((s) => s !== "") const showAll = args[2] let showAllQuestionsAtOnce: Store = state.userRelatedState?.showAllQuestionsAtOnce if (showAll === "yes") { showAllQuestionsAtOnce = new ImmutableStore(true) } else if (showAll === "no") { showAllQuestionsAtOnce = new ImmutableStore(false) } return new SvelteUIElement(Questionbox, { layer, tags, selectedElement: feature, state, onlyForLabels: labels, notForLabels: blacklist, showAllQuestionsAtOnce, }) } } class Minimap extends SpecialVisualizationSvelte { funcName = "minimap" docs = "A small map showing the selected feature." needsUrls = [] group = "default" args = [ { doc: "The (maximum) zoomlevel: the target zoomlevel after fitting the entire feature. The minimap will fit the entire feature, then zoom out to this zoom level. The higher, the more zoomed in with 1 being the entire world and 19 being really close", name: "zoomlevel", defaultValue: "18", }, { doc: "(Matches all resting arguments) This argument should be the key of a property of the feature. The corresponding value is interpreted as either the id or the a list of ID's. The features with these ID's will be shown on this minimap. (Note: if the key is 'id', list interpration is disabled)", name: "idKey", defaultValue: "id", }, ] example = "`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`" constr( state: SpecialVisualizationState, tagSource: UIEventSource>, args: string[], feature: Feature, ): SvelteUIElement { return new SvelteUIElement(MinimapViz, { state, args, feature, tagSource }) } } class SplitButton extends SpecialVisualizationSvelte { funcName = "split_button" docs = "Adds a button which allows to split a way" args = [] group = "default" constr( state: SpecialVisualizationState, tagSource: UIEventSource>, ): SvelteUIElement { return new SvelteUIElement(SplitRoadWizard, { id: tagSource.map((pr) => pr.id), state, }) } } class MoveButton extends SpecialVisualizationSvelte { 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 = [] group = "default" constr( state: SpecialVisualizationState, tagSource: UIEventSource>, argument: string[], feature: Feature, layer: LayerConfig, ): SvelteUIElement { if (feature.geometry.type !== "Point") { return undefined } return new SvelteUIElement(MoveWizard, { state, featureToMove: feature, layer, }) } } class DeleteButton extends SpecialVisualizationSvelte { 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 = [] group = "default" constr( state: SpecialVisualizationState, tagSource: UIEventSource>, argument: string[], feature: Feature, layer: LayerConfig, ): SvelteUIElement { if (!layer.deletion) { return undefined } return new SvelteUIElement(DeleteWizard, { tags: tagSource, deleteConfig: layer.deletion, state, feature, layer, }) } } class QrCodeVis extends SpecialVisualizationSvelte { funcName = "qr_code" args = [ { name: "text", doc: "Extra text on the side of the QR-code", }, { name: "textClass", doc: "CSS class of the the side text", }, ] group = "default" docs = "Generates a QR-code to share the selected object" constr( state: SpecialVisualizationState, tags: UIEventSource>, argument: string[], feature: Feature, ): SvelteUIElement { const sideText = argument[0] const sideTextClass = argument[1] ?? "" return new SvelteUIElement(QrCode, { state, tags, feature, sideText, sideTextClass, }) } } class IfNothingKnown extends SpecialVisualizationSvelte { funcName = "if_nothing_known" args = [ { name: "text", doc: "Text to show", required: true, }, { name: "cssClasses", doc: "Classes to apply onto the text" }, ] group = "default" 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>, argument: string[], feature: Feature, layer: LayerConfig, ): SvelteUIElement { const text = argument[0] const cssClasses = argument[1] return new SvelteUIElement(NothingKnown, { state, tags: tagSource, layer, text, cssClasses, }) } } class AddNewPointVis extends SpecialVisualizationSvelte { 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 = [] group = "default" constr(state: SpecialVisualizationState, _, __, feature: GeoJSON): SvelteUIElement { const [lon, lat] = GeoOperations.centerpointCoordinates(feature) return new SvelteUIElement(AddNewPoint, { state, coordinate: { lon, lat }, }) } } class Translated extends SpecialVisualization { 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" group = "UI" args = [ { name: "key", type: "key", doc: "The attribute to interpret as json", defaultValue: "value", }, ] constr( state: SpecialVisualizationState, tagSource: UIEventSource>, argument: string[], ): BaseUIElement { return new VariableUiElement( tagSource.map((tags) => { const v = tags[argument[0] ?? "value"] try { const tr = typeof v === "string" ? JSON.parse(v) : v return new Translation(tr).SetClass("font-bold") } catch (e) { console.error("Cannot create a translation for", v, "due to", e) return JSON.stringify(v) } }), ) } } class TitleVis extends SpecialVisualizationSvelte { group = "UI" funcName = "title" args = [] 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`." constr( state: SpecialVisualizationState, tags: UIEventSource>, _: string[], feature: Feature, layer: LayerConfig, ) { return new SvelteUIElement(FeatureTitle, { state, tags, feature, layer }) } } class BracedVis extends SpecialVisualization { group = "UI" funcName = "braced" docs = "Show a literal text within braces" args = [ { name: "text", required: true, doc: "The value to show", }, ] constr( state: SpecialVisualizationState, tagSource: UIEventSource>, args: string[], feature: Feature, layer: LayerConfig, ): BaseUIElement { return new FixedUiElement("{" + args[0] + "}") } } class CreateCopyVis extends SpecialVisualizationSvelte { group= "UI" funcName="create_copy" docs = "Allow to create a copy of the current element" args = [] constr(state: SpecialVisualizationState, tags: UIEventSource>, argument: string[], feature: Feature, layer: LayerConfig): SvelteUIElement { try{ console.log(">>> create_copy invoked") return new SvelteUIElement(CreateCopy, {state, tags, argument, feature, layer} ) }catch (e) { console.error(">>> failed",e) } } } export class UISpecialVisualisations { public static initList(): SpecialVisualization[] { return [ new QuestionViz(), new Minimap(), new SplitButton(), new MoveButton(), new DeleteButton(), new QrCodeVis(), new IfNothingKnown(), new ShareLinkViz(), new AddNewPointVis(), new CreateCopyVis(), new Translated(), new BracedVis(), new TitleVis(), ] } }