diff --git a/src/Logic/UIEventSource.ts b/src/Logic/UIEventSource.ts index bb22df11cc..19b130ad57 100644 --- a/src/Logic/UIEventSource.ts +++ b/src/Logic/UIEventSource.ts @@ -534,7 +534,7 @@ class MappedStore extends Store { private update(): void { const newData = this._f(this._upstream.data) this._upstreamPingCount = this._upstreamCallbackHandler?.pingCount - if (this._data == newData) { + if (this._data === newData) { return } this._data = newData diff --git a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts index ee469715ae..9dd8fb4e58 100644 --- a/src/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/src/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -645,6 +645,7 @@ export class AddEditingElements extends DesugaringStep { } if (json.allowSplit && !ValidationUtils.hasSpecialVisualisation(json, "split_button")) { + json.tagRenderings ??= [] json.tagRenderings.push({ id: "split-button", render: { "*": "{split_button()}" }, @@ -653,6 +654,7 @@ export class AddEditingElements extends DesugaringStep { } if (json.allowMove && !ValidationUtils.hasSpecialVisualisation(json, "move_button")) { + json.tagRenderings ??= [] json.tagRenderings.push({ id: "move-button", render: { "*": "{move_button()}" }, diff --git a/src/Models/ThemeConfig/Conversion/Validation.ts b/src/Models/ThemeConfig/Conversion/Validation.ts index 33e35f3ee9..a174716090 100644 --- a/src/Models/ThemeConfig/Conversion/Validation.ts +++ b/src/Models/ThemeConfig/Conversion/Validation.ts @@ -1033,7 +1033,7 @@ export class ValidateLayer extends DesugaringStep { } { - const hasCondition = json.mapRendering?.filter( + const hasCondition = json.pointRendering?.filter( (mr) => mr["icon"] !== undefined && mr["icon"]["condition"] !== undefined ) if (hasCondition?.length > 0) { diff --git a/src/Models/ThemeConfig/Json/LayerConfigJson.ts b/src/Models/ThemeConfig/Json/LayerConfigJson.ts index 8643bdf46a..6be3fa6ceb 100644 --- a/src/Models/ThemeConfig/Json/LayerConfigJson.ts +++ b/src/Models/ThemeConfig/Json/LayerConfigJson.ts @@ -43,7 +43,6 @@ export interface LayerConfigJson { description?: Translatable /** - * * Question: Where should the data be fetched from? * title: Data Source * @@ -202,13 +201,13 @@ export interface LayerConfigJson { minzoomVisible?: number /** + * question: What title should be shown on the infobox? * The title shown in a popup for elements of this layer. * * group: title - * question: What title should be shown on the infobox? - * types: use a fixed translation ; Use a dynamic tagRendering ; use a fixed string for all languages + * types: use a fixed translation ; Use a dynamic tagRendering ; hidden * typesdefault: 1 - * + * type: translation */ title?: TagRenderingConfigJson | Translatable diff --git a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts index 63a094d8ee..9151efb641 100644 --- a/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts +++ b/src/Models/ThemeConfig/Json/PointRenderingConfigJson.ts @@ -2,7 +2,17 @@ import { TagRenderingConfigJson } from "./TagRenderingConfigJson" import { TagConfigJson } from "./TagConfigJson" export interface IconConfigJson { + /** + * question: What icon should be used? + * type: icon + * suggestions: return ["pin","square","circle","checkmark","clock","close","crosshair","help","home","invalid","location","location_empty","location_locked","note","resolved","ring","scissors","teardrop","teardrop_with_hole_green","triangle"].map(i => ({if: "value="+i, then: i, icon: i})) + */ icon: string | TagRenderingConfigJson | { builtin: string; override: any } + /** + * question: What colour should the icon be? + * This will only work for the default icons such as `pin`,`circle`,... + * type: color + */ color?: string | TagRenderingConfigJson | { builtin: string; override: any } } @@ -23,18 +33,16 @@ export default interface PointRenderingConfigJson { location: ("point" | "centroid" | "start" | "end" | "projected_centerpoint" | string)[] /** - * question: What marker should be used to - * The icon for an element. - * Note that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets. - * - * The result of the icon is rendered as follows: - * the resulting string is interpreted as a _list_ of items, separated by ";". The bottommost layer is the first layer. - * As a result, on could use a generic pin, then overlay it with a specific icon. - * To make things even more practical, one c an use all SVG's from the folder "assets/svg" and _substitute the color_ in it. - * E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;` - - * Type: icon - */ + * The marker for an element. + * Note that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets. + * + * The result of the icon is rendered as follows: + * - The first icon is rendered on the map + * - The second entry is overlayed on top of it + * - ... + * + * As a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon. + */ marker?: IconConfigJson[] /** @@ -53,8 +61,9 @@ export default interface PointRenderingConfigJson { }[] /** - * A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ... - * Default is '40,40,center' + * question: What size should the marker be on the map? + * A string containing "," in pixels + * ifunset: Use the default size (40,40 px) */ iconSize?: string | TagRenderingConfigJson @@ -69,13 +78,15 @@ export default interface PointRenderingConfigJson { anchor?: "center" | "top" | "bottom" | "left" | "right" | string | TagRenderingConfigJson /** - * The rotation of an icon, useful for e.g. directions. - * Usage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)`` + * question: What rotation should be applied on the icon? + * This is mostly useful for items that face a specific direction, such as surveillance cameras + * This is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)`` + * ifunset: Do not rotate */ rotation?: string | TagRenderingConfigJson /** * question: What label should be shown beneath the marker? - * For example:
{name}
+ * For example: `<div style="background: white">{name}</div>` * * If the icon is undefined, then the label is shown in the center of the feature. * types: Dynamic value | string @@ -124,15 +135,15 @@ export default interface PointRenderingConfigJson { labelCssClasses?: string | TagRenderingConfigJson /** - * If the map is pitched, the marker will stay parallel to the screen. - * Set to 'map' if you want to put it flattened on the map + * question: If the map is pitched, should the icon stay parallel to the screen or to the groundplane? + * suggestions: return [{if: "value=canvas", then: "The icon will stay upward and not be transformed as if it sticks to the screen"}, {if: "value=map", then: "The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)"}] */ pitchAlignment?: "canvas" | "map" | TagRenderingConfigJson /** - * question: Should the icon be rotated or tilted if the map is rotated or tilted? + * question: Should the icon be rotated if the map is rotated? * ifunset: Do not rotate or tilt icons. Always keep the icons straight - * suggestions: return [{if: "value=canvas", then: "If the map is tilted, tilt the icon as well. This gives the impression of an icon that is glued to the ground."}, {if: "value=map", then: "If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground."}] + * suggestions: return [{if: "value=canvas", then: "Never rotate the icon"}, {if: "value=map", then: "If the map is rotated, rotate the icon as well. This gives the impression of an icon that floats perpendicular above the ground."}] */ rotationAlignment?: "map" | "canvas" | TagRenderingConfigJson } diff --git a/src/Models/ThemeConfig/PointRenderingConfig.ts b/src/Models/ThemeConfig/PointRenderingConfig.ts index 3cefb94bf1..389548b89d 100644 --- a/src/Models/ThemeConfig/PointRenderingConfig.ts +++ b/src/Models/ThemeConfig/PointRenderingConfig.ts @@ -5,7 +5,7 @@ import { TagUtils } from "../../Logic/Tags/TagUtils" import { Utils } from "../../Utils" import Svg from "../../Svg" import WithContextLoader from "./WithContextLoader" -import { Store } from "../../Logic/UIEventSource" +import { ImmutableStore, Store } from "../../Logic/UIEventSource" import BaseUIElement from "../../UI/BaseUIElement" import { FixedUiElement } from "../../UI/Base/FixedUiElement" import Img from "../../UI/Base/Img" @@ -93,7 +93,7 @@ export default class PointRenderingConfig extends WithContextLoader { ".location)" ) } - this.marker = (json.marker ?? []).map((m) => new IconConfig(m)) + this.marker = (json.marker ?? []).map((m) => new IconConfig(m)) if (json.css !== undefined) { this.cssDef = this.tr("css", undefined) } @@ -192,7 +192,7 @@ export default class PointRenderingConfig extends WithContextLoader { } public GetBaseIcon(tags?: Record): BaseUIElement { - return new SvelteUIElement(Marker, { icons: this.marker, tags }) + return new SvelteUIElement(Marker, { config: this, tags: new ImmutableStore(tags) }) } public RenderIcon( tags: Store>, diff --git a/src/UI/Base/NextButton.svelte b/src/UI/Base/NextButton.svelte index 6b4a64dd83..687417b53f 100644 --- a/src/UI/Base/NextButton.svelte +++ b/src/UI/Base/NextButton.svelte @@ -20,6 +20,6 @@
- + = 0? "h-4 w-4 shrink-0": "h-12 w-12 shrink-0" }/>
diff --git a/src/UI/InputElement/ValidatedInput.svelte b/src/UI/InputElement/ValidatedInput.svelte index 5fed1ea239..96271d7e28 100644 --- a/src/UI/InputElement/ValidatedInput.svelte +++ b/src/UI/InputElement/ValidatedInput.svelte @@ -79,7 +79,7 @@ onDestroy(_value.addCallbackAndRun((_) => setValues())) onDestroy(value.addCallbackAndRunD(fromUpstream => { - if(_value.data !== fromUpstream){ + if(_value.data !== fromUpstream && fromUpstream !== ""){ _value.setData(fromUpstream) } })) diff --git a/src/UI/InputElement/Validators.ts b/src/UI/InputElement/Validators.ts index c71121ad52..62be469a45 100644 --- a/src/UI/InputElement/Validators.ts +++ b/src/UI/InputElement/Validators.ts @@ -25,6 +25,7 @@ import TranslationValidator from "./Validators/TranslationValidator" import FediverseValidator from "./Validators/FediverseValidator" import IconValidator from "./Validators/IconValidator" import TagValidator from "./Validators/TagValidator" +import IdValidator from "./Validators/IdValidator" export type ValidatorType = (typeof Validators.availableTypes)[number] @@ -54,6 +55,7 @@ export default class Validators { "fediverse", "tag", "fediverse", + "id", ] as const public static readonly AllValidators: ReadonlyArray = [ @@ -80,6 +82,7 @@ export default class Validators { new TranslationValidator(), new IconValidator(), new FediverseValidator(), + new IdValidator(), ] private static _byType = Validators._byTypeConstructor() diff --git a/src/UI/InputElement/Validators/IconValidator.ts b/src/UI/InputElement/Validators/IconValidator.ts index da35c6d3e7..da6959fa81 100644 --- a/src/UI/InputElement/Validators/IconValidator.ts +++ b/src/UI/InputElement/Validators/IconValidator.ts @@ -11,7 +11,12 @@ export default class IconValidator extends Validator { super("icon", "Makes sure that a valid .svg-path is added") } + reformat(s: string, _?: () => string): string { + return s.trim() + } + getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined { + s = this.reformat(s) if (!s.startsWith("http")) { if (!IconValidator.allLicenses.has(s)) { const close = sloppy diff --git a/src/UI/InputElement/Validators/IdValidator.ts b/src/UI/InputElement/Validators/IdValidator.ts index e69de29bb2..04ffdfcdfb 100644 --- a/src/UI/InputElement/Validators/IdValidator.ts +++ b/src/UI/InputElement/Validators/IdValidator.ts @@ -0,0 +1,29 @@ +import { Translation } from "../../i18n/Translation" +import { Validator } from "../Validator" +import Translations from "../../i18n/Translations" + +export default class IdValidator extends Validator { + constructor() { + super( + "id", + "Checks for valid identifiers for layers, will automatically replace spaces and uppercase" + ) + } + isValid(key: string, getCountry?: () => string): boolean { + return this.getFeedback(key, getCountry) === undefined + } + + reformat(s: string, _?: () => string): string { + return s.replaceAll(" ", "_").toLowerCase() + } + + getFeedback(s: string, _?: () => string): Translation | undefined { + if (s.length < 3) { + return Translations.t.validation.id.shouldBeLonger + } + if (!s.match(/^[a-zA-Z0-9_ ]+$/)) { + return Translations.t.validation.id.invalidCharacter + } + return undefined + } +} diff --git a/src/UI/Map/Marker.svelte b/src/UI/Map/Marker.svelte index ab941b62b1..26864a3ba1 100644 --- a/src/UI/Map/Marker.svelte +++ b/src/UI/Map/Marker.svelte @@ -7,14 +7,15 @@ /** * Renders a 'marker', which consists of multiple 'icons' */ - export let config : PointRenderingConfig + export let config: PointRenderingConfig; let icons: IconConfig[] = config.marker; export let tags: Store>; - - -
- {#each icons as icon} - - {/each} -
+ +{#if config !== undefined} +
+ {#each icons as icon} + + {/each} +
+{/if} diff --git a/src/UI/Studio/EditLayer.svelte b/src/UI/Studio/EditLayer.svelte index 665f2a02c7..078360bc93 100644 --- a/src/UI/Studio/EditLayer.svelte +++ b/src/UI/Studio/EditLayer.svelte @@ -7,10 +7,12 @@ import { Store, UIEventSource } from "../../Logic/UIEventSource"; import type { ConfigMeta } from "./configMeta"; import { Utils } from "../../Utils"; + import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"; const layerSchema: ConfigMeta[] = layerSchemaRaw; let state = new EditLayerState(layerSchema); - state.configuration.setData({}); + export let initialLayerConfig: Partial = {} + state.configuration.setData(initialLayerConfig); const configuration = state.configuration; new LayerStateSender("http://localhost:1235", state); /** diff --git a/src/UI/Studio/EditLayerState.ts b/src/UI/Studio/EditLayerState.ts index 2be1524112..7ee98b54cb 100644 --- a/src/UI/Studio/EditLayerState.ts +++ b/src/UI/Studio/EditLayerState.ts @@ -129,7 +129,7 @@ export default class EditLayerState { } entry = entry[breadcrumb] } - if (v) { + if (v !== undefined && v !== null && v !== "") { entry[path.at(-1)] = v } else if (entry) { delete entry[path.at(-1)] diff --git a/src/UI/Studio/SchemaBasedField.svelte b/src/UI/Studio/SchemaBasedField.svelte index ebb9509615..3cd1996547 100644 --- a/src/UI/Studio/SchemaBasedField.svelte +++ b/src/UI/Studio/SchemaBasedField.svelte @@ -72,11 +72,11 @@ configJson.mappings.push( { if: "value=true", - then: "Yes "+(schema.hints?.iftrue??"") + then: "Yes: "+(schema.hints?.iftrue??"") }, { if: "value=false", - then: "No "+(schema.hints?.iffalse??"") + then: "No: "+(schema.hints?.iffalse??"") } ) } @@ -106,6 +106,15 @@ if (schema.type === "boolan") { return v === "true" || v === "yes" || v === "1" } + if(mightBeBoolean(schema.type)){ + if(v === "true" || v === "yes" || v === "1"){ + return true + } + if(v === "false" || v === "no" || v === "0"){ + console.log("Setting false...") + return false + } + } if (schema.type === "number") { return Number(v) } diff --git a/src/UI/Studio/SchemaBasedInput.svelte b/src/UI/Studio/SchemaBasedInput.svelte index ab6a6dc09c..77d823673b 100644 --- a/src/UI/Studio/SchemaBasedInput.svelte +++ b/src/UI/Studio/SchemaBasedInput.svelte @@ -4,9 +4,8 @@ import EditLayerState from "./EditLayerState"; import SchemaBasedArray from "./SchemaBasedArray.svelte"; import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte"; - import SchemaBasedTranslationInput from "./SchemaBasedTranslationInput.svelte"; - import { ConfigMetaUtils } from "./configMeta.ts" import ArrayMultiAnswer from "./ArrayMultiAnswer.svelte"; + export let schema: ConfigMeta; export let state: EditLayerState; export let path: (string | number)[] = []; diff --git a/src/UI/Studio/SchemaBasedMultiType.svelte b/src/UI/Studio/SchemaBasedMultiType.svelte index ac9cb5c3f0..75f4e75029 100644 --- a/src/UI/Studio/SchemaBasedMultiType.svelte +++ b/src/UI/Studio/SchemaBasedMultiType.svelte @@ -13,6 +13,7 @@ import type { JsonSchemaType } from "./jsonSchema"; // @ts-ignore import nmd from "nano-markdown"; + import { writable } from "svelte/store"; /** * If 'types' is defined: allow the user to pick one of the types to input. @@ -84,7 +85,7 @@ ); } const config = new TagRenderingConfig(configJson, "config based on " + schema.path.join(".")); - let chosenOption: number = defaultOption; + let chosenOption: number = writable(defaultOption); const existingValue = state.getCurrentValueFor(path); @@ -126,8 +127,11 @@ } possibleTypes.sort((a, b) => b.optionalMatches - a.optionalMatches); possibleTypes.sort((a, b) => b.matchingPropertiesCount - a.matchingPropertiesCount); + console.log("Possible types are", possibleTypes) if (possibleTypes.length > 0) { - tags.setData({ chosen_type_index: "" + possibleTypes[0].index }); + chosenOption = possibleTypes[0].index + tags.setData({ chosen_type_index: "" + chosenOption}); + } } else if (defaultOption !== undefined) { tags.setData({ chosen_type_index: "" + defaultOption }); @@ -150,13 +154,14 @@ let subSchemas: ConfigMeta[] = []; let subpath = path; - console.log("Initial chosen option is", chosenOption); + console.log("Initial chosen option for",path.join("."),"is", chosenOption); onDestroy(tags.addCallbackAndRun(tags => { if (tags["value"] !== "") { chosenOption = undefined; return; } const oldOption = chosenOption; + console.log("Updating chosenOption based on", tags, oldOption) chosenOption = tags["chosen_type_index"] ? Number(tags["chosen_type_index"]) : defaultOption; const type = schema.type[chosenOption]; if (chosenOption !== oldOption) { @@ -209,4 +214,5 @@ path={[...subpath, (subschema?.path?.at(-1) ?? "???")]}> {/each} {/if} + {chosenOption} diff --git a/src/UI/StudioGUI.svelte b/src/UI/StudioGUI.svelte index 6e2dbad2ac..254a216053 100644 --- a/src/UI/StudioGUI.svelte +++ b/src/UI/StudioGUI.svelte @@ -1,7 +1,87 @@ - + + import NextButton from "./Base/NextButton.svelte"; + import { Utils } from "../Utils"; + import { UIEventSource } from "../Logic/UIEventSource"; + import Constants from "../Models/Constants"; + import ValidatedInput from "./InputElement/ValidatedInput.svelte"; + import EditLayerState from "./Studio/EditLayerState"; + import EditLayer from "./Studio/EditLayer.svelte"; + import Loading from "../assets/svg/Loading.svelte"; + + + export let studioUrl = "http://127.0.0.1:1235"; + let overview = UIEventSource.FromPromise<{ allFiles: string[] }>(Utils.downloadJson(studioUrl + "/overview")); + let layers = overview.map(overview => { + if (!overview) { + return []; + } + return overview.allFiles.filter(f => f.startsWith("layers/") + ).map(l => l.substring(l.lastIndexOf("/") + 1, l.length - ".json".length)) + .filter(layerId => Constants.priviliged_layers.indexOf(layerId) < 0); + }); + let state: undefined | "edit_layer" | "new_layer" | "edit_theme" | "new_theme" | "editing_layer" | "loading" = undefined; + + let initialLayerConfig: undefined; + let newLayerId = new UIEventSource(""); + let layerIdFeedback = new UIEventSource(undefined); + newLayerId.addCallbackD(layerId => { + if (layerId === "") { + return; + } + if (layers.data.indexOf(layerId) >= 0) { + layerIdFeedback.setData("This id is already used"); + } + }, [layers]); + + + let editLayerState = new EditLayerState(); + + +{#if state === undefined} +

MapComplete Studio

+
+ + state = "edit_layer"}> + Edit an existing layer + + state = "new_layer"}> + Create a new layer + + state = "edit_theme"}> + Edit a theme + + state = "new_theme"}> + Create a new theme + +
+{:else if state === "edit_layer"} +
+ {#each $layers as layerId} + { + console.log("Editing layer",layerId) + state = "loading" + initialLayerConfig = await Utils.downloadJson(studioUrl+"/layers/"+layerId+"/"+layerId+".json") + state = "editing_layer" + }}> + {layerId} + + {/each} +
+{:else if state === "new_layer"} + + {#if $layerIdFeedback !== undefined} +
+ {$layerIdFeedback} +
+ {:else } + {initialLayerConfig = ({id: newLayerId.data}); state = "editing_layer"}}> + Create this layer + + {/if} +{:else if state === "loading"} + +{:else if state === "editing_layer"} + +{/if} diff --git a/src/assets/schemas/layerconfigmeta.json b/src/assets/schemas/layerconfigmeta.json index 7cfbc4b27f..892b42fec4 100644 --- a/src/assets/schemas/layerconfigmeta.json +++ b/src/assets/schemas/layerconfigmeta.json @@ -389,7 +389,8 @@ ], "required": false, "hints": { - "types": "use a fixed translation ; Use a dynamic tagRendering ; use a fixed string for all languages", + "typehint": "translation", + "types": "use a fixed translation ; Use a dynamic tagRendering ; hidden", "typesdefault": "1", "group": "title", "question": "What title should be shown on the infobox?" @@ -1621,12 +1622,318 @@ "marker" ], "required": false, + "hints": {}, + "type": "array", + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon." + }, + { + "path": [ + "pointRendering", + "marker", + "icon" + ], + "required": true, "hints": { "typehint": "icon", - "question": "What marker should be used to" + "question": "What icon should be used?", + "suggestions": [ + { + "if": "value=pin", + "then": "pin", + "icon": "pin" + }, + { + "if": "value=square", + "then": "square", + "icon": "square" + }, + { + "if": "value=circle", + "then": "circle", + "icon": "circle" + }, + { + "if": "value=checkmark", + "then": "checkmark", + "icon": "checkmark" + }, + { + "if": "value=clock", + "then": "clock", + "icon": "clock" + }, + { + "if": "value=close", + "then": "close", + "icon": "close" + }, + { + "if": "value=crosshair", + "then": "crosshair", + "icon": "crosshair" + }, + { + "if": "value=help", + "then": "help", + "icon": "help" + }, + { + "if": "value=home", + "then": "home", + "icon": "home" + }, + { + "if": "value=invalid", + "then": "invalid", + "icon": "invalid" + }, + { + "if": "value=location", + "then": "location", + "icon": "location" + }, + { + "if": "value=location_empty", + "then": "location_empty", + "icon": "location_empty" + }, + { + "if": "value=location_locked", + "then": "location_locked", + "icon": "location_locked" + }, + { + "if": "value=note", + "then": "note", + "icon": "note" + }, + { + "if": "value=resolved", + "then": "resolved", + "icon": "resolved" + }, + { + "if": "value=ring", + "then": "ring", + "icon": "ring" + }, + { + "if": "value=scissors", + "then": "scissors", + "icon": "scissors" + }, + { + "if": "value=teardrop", + "then": "teardrop", + "icon": "teardrop" + }, + { + "if": "value=teardrop_with_hole_green", + "then": "teardrop_with_hole_green", + "icon": "teardrop_with_hole_green" + }, + { + "if": "value=triangle", + "then": "triangle", + "icon": "triangle" + } + ] }, - "type": "array", - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one c an use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`" + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "" }, { "path": [ @@ -2131,6 +2438,213 @@ "type": "string", "description": "A list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\nValues are split on ` ` (space)" }, + { + "path": [ + "pointRendering", + "marker", + "color" + ], + "required": false, + "hints": { + "typehint": "color", + "question": "What colour should the icon be?" + }, + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "This will only work for the default icons such as `pin`,`circle`,..." + }, { "path": [ "pointRendering", @@ -3380,7 +3894,10 @@ "iconSize" ], "required": false, - "hints": {}, + "hints": { + "question": "What size should the marker be on the map?", + "ifunset": "Use the default size (40,40 px)" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -3562,7 +4079,7 @@ "type": "string" } ], - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'" + "description": "A string containing \",\" in pixels" }, { "path": [ @@ -4751,7 +5268,10 @@ "rotation" ], "required": false, - "hints": {}, + "hints": { + "question": "What rotation should be applied on the icon?", + "ifunset": "Do not rotate" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -4933,7 +5453,7 @@ "type": "string" } ], - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" + "description": "This is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" }, { "path": [ @@ -5610,7 +6130,7 @@ "type": "string" } ], - "description": "For example:
{name}
\nIf the icon is undefined, then the label is shown in the center of the feature." + "description": "For example: `<div style=\"background: white\">{name}</div>`\nIf the icon is undefined, then the label is shown in the center of the feature." }, { "path": [ @@ -8809,7 +9329,19 @@ "pitchAlignment" ], "required": false, - "hints": {}, + "hints": { + "question": "If the map is pitched, should the icon stay parallel to the screen or to the groundplane?", + "suggestions": [ + { + "if": "value=canvas", + "then": "The icon will stay upward and not be transformed as if it sticks to the screen" + }, + { + "if": "value=map", + "then": "The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)" + } + ] + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -8995,7 +9527,7 @@ "type": "string" } ], - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map" + "description": "" }, { "path": [ @@ -9487,12 +10019,12 @@ ], "required": false, "hints": { - "question": "Should the icon be rotated or tilted if the map is rotated or tilted?", + "question": "Should the icon be rotated if the map is rotated?", "ifunset": "Do not rotate or tilt icons. Always keep the icons straight", "suggestions": [ { "if": "value=canvas", - "then": "If the map is tilted, tilt the icon as well. This gives the impression of an icon that is glued to the ground." + "then": "Never rotate the icon" }, { "if": "value=map", diff --git a/src/assets/schemas/layoutconfigmeta.json b/src/assets/schemas/layoutconfigmeta.json index 9a7df6e672..643d66b5f1 100644 --- a/src/assets/schemas/layoutconfigmeta.json +++ b/src/assets/schemas/layoutconfigmeta.json @@ -328,7 +328,7 @@ "type": "number" }, "title": { - "description": "The title shown in a popup for elements of this layer.\n\ngroup: title\nquestion: What title should be shown on the infobox?\ntypes: use a fixed translation ; Use a dynamic tagRendering ; use a fixed string for all languages\ntypesdefault: 1", + "description": "question: What title should be shown on the infobox?\nThe title shown in a popup for elements of this layer.\n\ngroup: title\ntypes: use a fixed translation ; Use a dynamic tagRendering ; hidden\ntypesdefault: 1\ntype: translation", "anyOf": [ { "$ref": "#/definitions/Record" @@ -1492,7 +1492,8 @@ ], "required": false, "hints": { - "types": "use a fixed translation ; Use a dynamic tagRendering ; use a fixed string for all languages", + "typehint": "translation", + "types": "use a fixed translation ; Use a dynamic tagRendering ; hidden", "typesdefault": "1", "group": "title", "question": "What title should be shown on the infobox?" @@ -2770,12 +2771,319 @@ "marker" ], "required": false, + "hints": {}, + "type": "array", + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon." + }, + { + "path": [ + "layers", + "pointRendering", + "marker", + "icon" + ], + "required": true, "hints": { "typehint": "icon", - "question": "What marker should be used to" + "question": "What icon should be used?", + "suggestions": [ + { + "if": "value=pin", + "then": "pin", + "icon": "pin" + }, + { + "if": "value=square", + "then": "square", + "icon": "square" + }, + { + "if": "value=circle", + "then": "circle", + "icon": "circle" + }, + { + "if": "value=checkmark", + "then": "checkmark", + "icon": "checkmark" + }, + { + "if": "value=clock", + "then": "clock", + "icon": "clock" + }, + { + "if": "value=close", + "then": "close", + "icon": "close" + }, + { + "if": "value=crosshair", + "then": "crosshair", + "icon": "crosshair" + }, + { + "if": "value=help", + "then": "help", + "icon": "help" + }, + { + "if": "value=home", + "then": "home", + "icon": "home" + }, + { + "if": "value=invalid", + "then": "invalid", + "icon": "invalid" + }, + { + "if": "value=location", + "then": "location", + "icon": "location" + }, + { + "if": "value=location_empty", + "then": "location_empty", + "icon": "location_empty" + }, + { + "if": "value=location_locked", + "then": "location_locked", + "icon": "location_locked" + }, + { + "if": "value=note", + "then": "note", + "icon": "note" + }, + { + "if": "value=resolved", + "then": "resolved", + "icon": "resolved" + }, + { + "if": "value=ring", + "then": "ring", + "icon": "ring" + }, + { + "if": "value=scissors", + "then": "scissors", + "icon": "scissors" + }, + { + "if": "value=teardrop", + "then": "teardrop", + "icon": "teardrop" + }, + { + "if": "value=teardrop_with_hole_green", + "then": "teardrop_with_hole_green", + "icon": "teardrop_with_hole_green" + }, + { + "if": "value=triangle", + "then": "triangle", + "icon": "triangle" + } + ] }, - "type": "array", - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one c an use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`" + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "" }, { "path": [ @@ -3300,6 +3608,214 @@ "type": "string", "description": "A list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\nValues are split on ` ` (space)" }, + { + "path": [ + "layers", + "pointRendering", + "marker", + "color" + ], + "required": false, + "hints": { + "typehint": "color", + "question": "What colour should the icon be?" + }, + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "This will only work for the default icons such as `pin`,`circle`,..." + }, { "path": [ "layers", @@ -4593,7 +5109,10 @@ "iconSize" ], "required": false, - "hints": {}, + "hints": { + "question": "What size should the marker be on the map?", + "ifunset": "Use the default size (40,40 px)" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -4775,7 +5294,7 @@ "type": "string" } ], - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'" + "description": "A string containing \",\" in pixels" }, { "path": [ @@ -6006,7 +6525,10 @@ "rotation" ], "required": false, - "hints": {}, + "hints": { + "question": "What rotation should be applied on the icon?", + "ifunset": "Do not rotate" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -6188,7 +6710,7 @@ "type": "string" } ], - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" + "description": "This is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" }, { "path": [ @@ -6886,7 +7408,7 @@ "type": "string" } ], - "description": "For example:
{name}
\nIf the icon is undefined, then the label is shown in the center of the feature." + "description": "For example: `<div style=\"background: white\">{name}</div>`\nIf the icon is undefined, then the label is shown in the center of the feature." }, { "path": [ @@ -10190,7 +10712,19 @@ "pitchAlignment" ], "required": false, - "hints": {}, + "hints": { + "question": "If the map is pitched, should the icon stay parallel to the screen or to the groundplane?", + "suggestions": [ + { + "if": "value=canvas", + "then": "The icon will stay upward and not be transformed as if it sticks to the screen" + }, + { + "if": "value=map", + "then": "The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)" + } + ] + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -10376,7 +10910,7 @@ "type": "string" } ], - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map" + "description": "" }, { "path": [ @@ -10889,12 +11423,12 @@ ], "required": false, "hints": { - "question": "Should the icon be rotated or tilted if the map is rotated or tilted?", + "question": "Should the icon be rotated if the map is rotated?", "ifunset": "Do not rotate or tilt icons. Always keep the icons straight", "suggestions": [ { "if": "value=canvas", - "then": "If the map is tilted, tilt the icon as well. This gives the impression of an icon that is glued to the ground." + "then": "Never rotate the icon" }, { "if": "value=map", @@ -18814,7 +19348,8 @@ ], "required": false, "hints": { - "types": "use a fixed translation ; Use a dynamic tagRendering ; use a fixed string for all languages", + "typehint": "translation", + "types": "use a fixed translation ; Use a dynamic tagRendering ; hidden", "typesdefault": "1", "group": "title", "question": "What title should be shown on the infobox?" @@ -20138,12 +20673,320 @@ "marker" ], "required": false, + "hints": {}, + "type": "array", + "description": "The marker for an element.\nNote that this also defines the icon for this layer (rendered with the overpass-tags) and the icon in the presets.\nThe result of the icon is rendered as follows:\n- The first icon is rendered on the map\n- The second entry is overlayed on top of it\n- ...\nAs a result, on could use a generic icon (`pin`, `circle`, `square`) with a color, then overlay it with a specific icon." + }, + { + "path": [ + "layers", + "override", + "pointRendering", + "marker", + "icon" + ], + "required": true, "hints": { "typehint": "icon", - "question": "What marker should be used to" + "question": "What icon should be used?", + "suggestions": [ + { + "if": "value=pin", + "then": "pin", + "icon": "pin" + }, + { + "if": "value=square", + "then": "square", + "icon": "square" + }, + { + "if": "value=circle", + "then": "circle", + "icon": "circle" + }, + { + "if": "value=checkmark", + "then": "checkmark", + "icon": "checkmark" + }, + { + "if": "value=clock", + "then": "clock", + "icon": "clock" + }, + { + "if": "value=close", + "then": "close", + "icon": "close" + }, + { + "if": "value=crosshair", + "then": "crosshair", + "icon": "crosshair" + }, + { + "if": "value=help", + "then": "help", + "icon": "help" + }, + { + "if": "value=home", + "then": "home", + "icon": "home" + }, + { + "if": "value=invalid", + "then": "invalid", + "icon": "invalid" + }, + { + "if": "value=location", + "then": "location", + "icon": "location" + }, + { + "if": "value=location_empty", + "then": "location_empty", + "icon": "location_empty" + }, + { + "if": "value=location_locked", + "then": "location_locked", + "icon": "location_locked" + }, + { + "if": "value=note", + "then": "note", + "icon": "note" + }, + { + "if": "value=resolved", + "then": "resolved", + "icon": "resolved" + }, + { + "if": "value=ring", + "then": "ring", + "icon": "ring" + }, + { + "if": "value=scissors", + "then": "scissors", + "icon": "scissors" + }, + { + "if": "value=teardrop", + "then": "teardrop", + "icon": "teardrop" + }, + { + "if": "value=teardrop_with_hole_green", + "then": "teardrop_with_hole_green", + "icon": "teardrop_with_hole_green" + }, + { + "if": "value=triangle", + "then": "triangle", + "icon": "triangle" + } + ] }, - "type": "array", - "description": "The icon for an element.\nNote that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.\nThe result of the icon is rendered as follows:\nthe resulting string is interpreted as a _list_ of items, separated by \";\". The bottommost layer is the first layer.\nAs a result, on could use a generic pin, then overlay it with a specific icon.\nTo make things even more practical, one c an use all SVG's from the folder \"assets/svg\" and _substitute the color_ in it.\nE.g. to draw a red pin, use \"pin:#f00\", to have a green circle with your icon on top, use `circle:#0f0;`" + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "" }, { "path": [ @@ -20688,6 +21531,215 @@ "type": "string", "description": "A list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\nValues are split on ` ` (space)" }, + { + "path": [ + "layers", + "override", + "pointRendering", + "marker", + "color" + ], + "required": false, + "hints": { + "typehint": "color", + "question": "What colour should the icon be?" + }, + "type": [ + { + "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", + "type": "object", + "properties": { + "render": { + "description": "question: What text should be rendered?\n\nThis piece of text will be shown in the infobox.\nNote that \"&LBRACEkey&RBRACE\"-parts are substituted by the corresponding values of the element.\n\nThis text will be shown if:\n- there is no mapping which matches (or there are no matches)\n- no question, no mappings and no 'freeform' is set\n\nNote that this is a HTML-interpreted value, so you can add links as e.g. '<a href='{website}'>{website}</a>' or include images such as `This is of type A <br><img src='typeA-icon.svg' />`\ntype: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "object", + "properties": { + "special": { + "allOf": [ + { + "$ref": "#/definitions/Record>" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + } + }, + "required": [ + "special" + ] + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: what icon should be shown next to the 'render' value?\nAn icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + }, + "condition": { + "description": "question: When should this item be shown?\n\nOnly show this tagrendering (or ask the question) if the selected object also matches the tags specified as `condition`.\n\nThis is useful to ask a follow-up question.\nFor example, within toilets, asking _where_ the diaper changing table is is only useful _if_ there is one.\nThis can be done by adding `\"condition\": \"changing_table=yes\"`\n\nA full example would be:\n```json\n {\n \"question\": \"Where is the changing table located?\",\n \"render\": \"The changing table is located at {changing_table:location}\",\n \"condition\": \"changing_table=yes\",\n \"freeform\": {\n \"key\": \"changing_table:location\",\n \"inline\": true\n },\n \"mappings\": [\n {\n \"then\": \"The changing table is in the toilet for women.\",\n \"if\": \"changing_table:location=female_toilet\"\n },\n {\n \"then\": \"The changing table is in the toilet for men.\",\n \"if\": \"changing_table:location=male_toilet\"\n },\n {\n \"if\": \"changing_table:location=wheelchair_toilet\",\n \"then\": \"The changing table is in the toilet for wheelchair users.\",\n },\n {\n \"if\": \"changing_table:location=dedicated_room\",\n \"then\": \"The changing table is in a dedicated room. \",\n }\n ],\n \"id\": \"toilet-changing_table:location\"\n },\n```", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "metacondition": { + "description": "question: When should this item be shown (including special conditions)?\n\nIf set, this tag will be evaluated agains the _usersettings/application state_ table.\nEnable 'show debug info' in user settings to see available options.\nNote that values with an underscore depicts _application state_ (including metainfo about the user) whereas values without an underscore depict _user settings_", + "anyOf": [ + { + "$ref": "#/definitions/{and:TagConfigJson[];}" + }, + { + "$ref": "#/definitions/{or:TagConfigJson[];}" + }, + { + "type": "string" + } + ] + }, + "freeform": { + "description": "question: Should a freeform text field be shown?\nAllow freeform text input from the user\nifunset: Do not add a freeform text field", + "type": "object", + "properties": { + "key": { + "description": "What attribute should be filled out\nIf this key is present in the feature, then 'render' is used to display the value.\nIf this is undefined, the rendering is _always_ shown", + "type": "string" + } + }, + "required": [ + "key" + ] + }, + "mappings": { + "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes", + "type": "array", + "items": { + "type": "object", + "properties": { + "if": { + "$ref": "#/definitions/TagConfigJson", + "description": "question: When should this single mapping match?\n\nIf this condition is met, then the text under `then` will be shown.\nIf no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM.\n\nFor example: {'if': 'diet:vegetarion=yes', 'then':'A vegetarian option is offered here'}\n\nThis can be an substituting-tag as well, e.g. {'if': 'addr:street:={_calculated_nearby_streetname}', 'then': '{_calculated_nearby_streetname}'}" + }, + "then": { + "description": "question: What text should be shown?\n\nIf the condition `if` is met, the text `then` will be rendered.\nIf not known yet, the user will be presented with `then` as an option\nType: rendered", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "icon": { + "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: {icon}\nType: icon", + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "path" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "if", + "then" + ] + } + }, + "description": { + "description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings", + "anyOf": [ + { + "$ref": "#/definitions/Record" + }, + { + "type": "string" + } + ] + }, + "classes": { + "description": "question: What css-classes should be applied to showing this attribute?\n\nA list of css-classes to apply to the entire tagRendering.\nThese classes are applied in 'answer'-mode, not in question mode\nThis is only for advanced users.\n\nValues are split on ` ` (space)", + "type": "string" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "builtin": { + "type": "string" + }, + "override": {} + }, + "required": [ + "builtin", + "override" + ] + }, + { + "type": "string" + } + ], + "description": "This will only work for the default icons such as `pin`,`circle`,..." + }, { "path": [ "layers", @@ -22025,7 +23077,10 @@ "iconSize" ], "required": false, - "hints": {}, + "hints": { + "question": "What size should the marker be on the map?", + "ifunset": "Use the default size (40,40 px)" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -22207,7 +23262,7 @@ "type": "string" } ], - "description": "A string containing \"width,height\" or \"width,height,anchorpoint\" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...\nDefault is '40,40,center'" + "description": "A string containing \",\" in pixels" }, { "path": [ @@ -23480,7 +24535,10 @@ "rotation" ], "required": false, - "hints": {}, + "hints": { + "question": "What rotation should be applied on the icon?", + "ifunset": "Do not rotate" + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -23662,7 +24720,7 @@ "type": "string" } ], - "description": "The rotation of an icon, useful for e.g. directions.\nUsage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" + "description": "This is mostly useful for items that face a specific direction, such as surveillance cameras\nThis is interpreted as css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``" }, { "path": [ @@ -24381,7 +25439,7 @@ "type": "string" } ], - "description": "For example:
{name}
\nIf the icon is undefined, then the label is shown in the center of the feature." + "description": "For example: `<div style=\"background: white\">{name}</div>`\nIf the icon is undefined, then the label is shown in the center of the feature." }, { "path": [ @@ -27790,7 +28848,19 @@ "pitchAlignment" ], "required": false, - "hints": {}, + "hints": { + "question": "If the map is pitched, should the icon stay parallel to the screen or to the groundplane?", + "suggestions": [ + { + "if": "value=canvas", + "then": "The icon will stay upward and not be transformed as if it sticks to the screen" + }, + { + "if": "value=map", + "then": "The icon will be transformed as if it were painted onto the ground. (Automatically sets rotationAlignment)" + } + ] + }, "type": [ { "description": "A TagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nFor an _editable_ tagRendering, use 'QuestionableTagRenderingConfigJson' instead, which extends this one", @@ -27976,7 +29046,7 @@ "type": "string" } ], - "description": "If the map is pitched, the marker will stay parallel to the screen.\nSet to 'map' if you want to put it flattened on the map" + "description": "" }, { "path": [ @@ -28510,12 +29580,12 @@ ], "required": false, "hints": { - "question": "Should the icon be rotated or tilted if the map is rotated or tilted?", + "question": "Should the icon be rotated if the map is rotated?", "ifunset": "Do not rotate or tilt icons. Always keep the icons straight", "suggestions": [ { "if": "value=canvas", - "then": "If the map is tilted, tilt the icon as well. This gives the impression of an icon that is glued to the ground." + "then": "Never rotate the icon" }, { "if": "value=map",