Studio: WIP

This commit is contained in:
Pieter Vander Vennet 2023-08-23 11:11:53 +02:00
parent 04ecdad1bb
commit 903e168a89
62 changed files with 19152 additions and 123399 deletions

View file

@ -576,6 +576,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -639,7 +663,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -696,10 +720,10 @@
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -710,7 +734,7 @@
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -734,7 +758,7 @@
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -751,7 +775,7 @@
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -765,18 +789,18 @@
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -790,7 +814,7 @@
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -1114,7 +1138,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1133,10 +1156,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1155,7 +1179,7 @@
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1168,7 +1192,7 @@
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1179,7 +1203,7 @@
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1233,6 +1257,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -1286,7 +1334,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1305,10 +1352,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1327,7 +1375,7 @@
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1340,7 +1388,7 @@
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1351,7 +1399,7 @@
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1405,6 +1453,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [

View file

@ -571,6 +571,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -634,7 +658,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -689,10 +713,10 @@ export default {
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -703,7 +727,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -727,7 +751,7 @@ export default {
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -744,7 +768,7 @@ export default {
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -758,18 +782,18 @@ export default {
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -783,7 +807,7 @@ export default {
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -1102,7 +1126,6 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1121,10 +1144,11 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1143,7 +1167,7 @@ export default {
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1156,7 +1180,7 @@ export default {
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1167,7 +1191,7 @@ export default {
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1221,6 +1245,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -1273,7 +1321,6 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1292,10 +1339,11 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1314,7 +1362,7 @@ export default {
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1327,7 +1375,7 @@ export default {
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1338,7 +1386,7 @@ export default {
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1392,6 +1440,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [

View file

@ -473,6 +473,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -536,7 +560,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -593,10 +617,10 @@
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -607,7 +631,7 @@
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -631,7 +655,7 @@
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -648,7 +672,7 @@
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -662,18 +686,18 @@
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -687,7 +711,7 @@
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -1011,7 +1035,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1030,10 +1053,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1052,7 +1076,7 @@
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1065,7 +1089,7 @@
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1076,7 +1100,7 @@
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1130,6 +1154,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -1183,7 +1231,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1202,10 +1249,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1224,7 +1272,7 @@
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1237,7 +1285,7 @@
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1248,7 +1296,7 @@
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1302,6 +1350,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [

View file

@ -468,6 +468,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -531,7 +555,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -586,10 +610,10 @@ export default {
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -600,7 +624,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -624,7 +648,7 @@ export default {
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -641,7 +665,7 @@ export default {
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -655,18 +679,18 @@ export default {
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -680,7 +704,7 @@ export default {
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -999,7 +1023,6 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1018,10 +1041,11 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1040,7 +1064,7 @@ export default {
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1053,7 +1077,7 @@ export default {
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1064,7 +1088,7 @@ export default {
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1118,6 +1142,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -1170,7 +1218,6 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -1189,10 +1236,11 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -1211,7 +1259,7 @@ export default {
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -1224,7 +1272,7 @@ export default {
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1235,7 +1283,7 @@ export default {
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -1289,6 +1337,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [

View file

@ -241,6 +241,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -304,7 +328,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -236,6 +236,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -299,7 +323,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -3,10 +3,10 @@
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -17,7 +17,7 @@
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -41,7 +41,7 @@
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -58,7 +58,7 @@
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -72,18 +72,18 @@
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -97,7 +97,7 @@
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -274,6 +274,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -337,7 +361,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -3,10 +3,10 @@ export default {
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -17,7 +17,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -41,7 +41,7 @@ export default {
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -58,7 +58,7 @@ export default {
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -72,18 +72,18 @@ export default {
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -97,7 +97,7 @@ export default {
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },
@ -269,6 +269,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -332,7 +356,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -339,6 +339,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -402,7 +426,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -334,6 +334,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -397,7 +421,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -3,7 +3,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -22,10 +21,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -44,7 +44,7 @@
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -57,7 +57,7 @@
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -68,7 +68,7 @@
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -122,6 +122,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -338,6 +362,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -401,7 +449,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -458,10 +506,10 @@
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -472,7 +520,7 @@
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -496,7 +544,7 @@
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -513,7 +561,7 @@
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -527,18 +575,18 @@
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -552,7 +600,7 @@
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },

View file

@ -3,7 +3,6 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n\nquestion: What is the id of this tagRendering?",
"type": "string" "type": "string"
}, },
"mappings": { "mappings": {
@ -22,10 +21,11 @@ export default {
"type": "object", "type": "object",
"properties": { "properties": {
"key": { "key": {
"description": "question What is the name of the attribute that should be written to?\nifunset: do not offer a freeform textfield as answer option",
"type": "string" "type": "string"
}, },
"type": { "type": {
"description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values", "description": "question: What is the input type?\nThe type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values\nsuggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: \"value=\"+type.name, then: \"<b>\"+type.name+\"</b> \"+type.explanation.split(\"\\n\")[0]}))",
"type": "string" "type": "string"
}, },
"placeholder": { "placeholder": {
@ -44,7 +44,7 @@ export default {
} }
}, },
"inline": { "inline": {
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present.", "description": "question: Show the freeform as box within the question?\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nifunset: do not show the",
"type": "boolean" "type": "boolean"
}, },
"default": { "default": {
@ -57,7 +57,7 @@ export default {
] ]
}, },
"question": { "question": {
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only", "description": "question: What question should be shown to the contributor?\n\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n\nifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -68,7 +68,7 @@ export default {
] ]
}, },
"questionHint": { "questionHint": {
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like", "description": "question: Should some extra information be shown to the contributor, alongside the question?\nThis hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like\nifunset: No extra hint is given",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -122,6 +122,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -333,6 +357,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -396,7 +444,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -451,10 +499,10 @@ export default {
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -465,7 +513,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -489,7 +537,7 @@ export default {
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -506,7 +554,7 @@ export default {
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -520,18 +568,18 @@ export default {
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -545,7 +593,7 @@ export default {
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },

View file

@ -201,6 +201,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -264,7 +288,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -321,10 +345,10 @@
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -335,7 +359,7 @@
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -359,7 +383,7 @@
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -376,7 +400,7 @@
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -390,18 +414,18 @@
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -415,7 +439,7 @@
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },

View file

@ -196,6 +196,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -259,7 +283,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -314,10 +338,10 @@ export default {
"properties": { "properties": {
"if": { "if": {
"$ref": "#/definitions/TagConfigJson", "$ref": "#/definitions/TagConfigJson",
"description": "quesiton: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object" "description": "question: What tags should be matched to show this option?\n\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
"then": { "then": {
"description": "Shown if the 'if is fulfilled\nType: rendered", "description": "Question: What corresponding text should be shown?\nShown if the `if` is fulfilled\nType: rendered",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -328,7 +352,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "An extra icon supporting the choice\nType: icon", "description": "question: What icon should be shown next to this mapping?\n\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n\nifunset: Show no icon\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",
@ -352,7 +376,7 @@ export default {
] ]
}, },
"hideInAnswer": { "hideInAnswer": {
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}", "description": "question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?\niftrue: Never show this mapping as option to pick\nifunset: Always show this mapping as option to pick\ntype: tag\n\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -369,7 +393,7 @@ export default {
] ]
}, },
"ifnot": { "ifnot": {
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`", "description": "question: What tags should be applied if this mapping is _not_ chosen?\n\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -383,18 +407,18 @@ export default {
] ]
}, },
"addExtraTags": { "addExtraTags": {
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```", "description": "question: What extra tags should be added to the object if this object is chosen?\ntype: simple_tag[]\n\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
} }
}, },
"searchTerms": { "searchTerms": {
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options", "description": "question: If there are many options, what search terms match too?\nIf there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options\ngroup: hidden",
"$ref": "#/definitions/Record<string,string[]>" "$ref": "#/definitions/Record<string,string[]>"
}, },
"priorityIf": { "priorityIf": {
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly", "description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly\ngroup: hidden",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -408,7 +432,7 @@ export default {
] ]
}, },
"#": { "#": {
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed", "description": "Used for comments or to disable a validation\n\ngroup: hidden\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed",
"type": "string" "type": "string"
} }
}, },

View file

@ -39,6 +39,30 @@
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -102,7 +126,7 @@
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -39,6 +39,30 @@ export default {
} }
] ]
}, },
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
]
},
"condition": { "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```", "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": [ "anyOf": [
@ -102,7 +126,7 @@ export default {
] ]
}, },
"icon": { "icon": {
"description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\nType: icon", "description": "question: What icon should be added to this mapping?\nAn icon supporting this mapping; typically shown pretty small\ninline: <img src='{icon}' class=\"w-8 h-8\" /> {icon}\nType: icon",
"anyOf": [ "anyOf": [
{ {
"type": "object", "type": "object",

View file

@ -11,8 +11,8 @@
"start": "npm run generate:layeroverview && npm run strt", "start": "npm run generate:layeroverview && npm run strt",
"strt": "vite --host", "strt": "vite --host",
"strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html assets/templates/*.svg assets/templates/fonts/*.ttf", "strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html assets/templates/*.svg assets/templates/fonts/*.ttf",
"watch:css": "tailwindcss -i index.css -o public/css/index-tailwind-output.css --watch", "watch:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i index.css -o public/css/index-tailwind-output.css", "generate:css": "tailwindcss -i src/index.css -o public/css/index-tailwind-output.css",
"generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts", "generate:doctests": "doctest-ts-improved . --ignore .*.spec.ts --ignore .*ConfigJson.ts",
"test:run-only": "vitest --run test", "test:run-only": "vitest --run test",
"test": " export NODE_OPTIONS=\"--max-old-space-size=8192\" && npm run clean:tests && (npm run generate:doctests 2>&1 | grep -v \"No doctests found in\") && npm run test:run-only && npm run clean:tests", "test": " export NODE_OPTIONS=\"--max-old-space-size=8192\" && npm run clean:tests && (npm run generate:doctests 2>&1 | grep -v \"No doctests found in\") && npm run test:run-only && npm run clean:tests",

View file

@ -698,16 +698,6 @@ video {
position: sticky; position: sticky;
} }
<<<<<<< HEAD
=======
.inset-0 {
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
}
>>>>>>> master
.-inset-1 { .-inset-1 {
top: -0.25rem; top: -0.25rem;
right: -0.25rem; right: -0.25rem;
@ -747,26 +737,6 @@ video {
bottom: 0px; bottom: 0px;
} }
.top-12 {
top: 3rem;
}
.left-3 {
left: 0.75rem;
}
.top-3 {
top: 0.75rem;
}
.right-2 {
right: 0.5rem;
}
.bottom-3 {
bottom: 0.75rem;
}
.right-1\/3 { .right-1\/3 {
right: 33.333333%; right: 33.333333%;
} }
@ -877,6 +847,11 @@ video {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.my-1 {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.mx-4 { .mx-4 {
margin-left: 1rem; margin-left: 1rem;
margin-right: 1rem; margin-right: 1rem;
@ -887,6 +862,10 @@ video {
margin-right: 3rem; margin-right: 3rem;
} }
.mb-4 {
margin-bottom: 1rem;
}
.mr-2 { .mr-2 {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
@ -919,10 +898,6 @@ video {
margin-right: 0.25rem; margin-right: 0.25rem;
} }
.mb-4 {
margin-bottom: 1rem;
}
.ml-1 { .ml-1 {
margin-left: 0.25rem; margin-left: 0.25rem;
} }
@ -1125,11 +1100,6 @@ video {
height: 1rem; height: 1rem;
} }
.h-min {
height: -webkit-min-content;
height: min-content;
}
.h-1\/2 { .h-1\/2 {
height: 50%; height: 50%;
} }
@ -1509,10 +1479,6 @@ video {
overflow: hidden; overflow: hidden;
} }
.overflow-scroll {
overflow: scroll;
}
.overflow-y-auto { .overflow-y-auto {
overflow-y: auto; overflow-y: auto;
} }
@ -1560,18 +1526,14 @@ video {
border-radius: 1rem; border-radius: 1rem;
} }
.rounded-3xl { .rounded-md {
border-radius: 1.5rem; border-radius: 0.375rem;
} }
.rounded-lg { .rounded-lg {
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.rounded-md {
border-radius: 0.375rem;
}
.rounded-sm { .rounded-sm {
border-radius: 0.125rem; border-radius: 0.125rem;
} }
@ -1642,7 +1604,6 @@ video {
border-bottom-width: 2px; border-bottom-width: 2px;
} }
<<<<<<< HEAD
.border-l-4 { .border-l-4 {
border-left-width: 4px; border-left-width: 4px;
} }
@ -1651,12 +1612,6 @@ video {
border-top-width: 1px; border-top-width: 1px;
} }
=======
.border-t {
border-top-width: 1px;
}
>>>>>>> master
.border-r { .border-r {
border-right-width: 1px; border-right-width: 1px;
} }
@ -1713,11 +1668,6 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity)); background-color: rgb(255 255 255 / var(--tw-bg-opacity));
} }
.bg-red-500 {
--tw-bg-opacity: 1;
background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}
.bg-black { .bg-black {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity)); background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@ -1754,10 +1704,6 @@ video {
padding: 0.5rem; padding: 0.5rem;
} }
.p-3 {
padding: 0.75rem;
}
.p-4 { .p-4 {
padding: 1rem; padding: 1rem;
} }
@ -1802,10 +1748,6 @@ video {
padding-right: 0.5rem; padding-right: 0.5rem;
} }
.pl-3 {
padding-left: 0.75rem;
}
.pl-2 { .pl-2 {
padding-left: 0.5rem; padding-left: 0.5rem;
} }
@ -1834,6 +1776,10 @@ video {
padding-left: 1rem; padding-left: 1rem;
} }
.pl-3 {
padding-left: 0.75rem;
}
.pr-0 { .pr-0 {
padding-right: 0px; padding-right: 0px;
} }
@ -1893,11 +1839,6 @@ video {
line-height: 1.5rem; line-height: 1.5rem;
} }
.text-xs {
font-size: 0.75rem;
line-height: 1rem;
}
.font-bold { .font-bold {
font-weight: 700; font-weight: 700;
} }
@ -2136,12 +2077,6 @@ video {
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
} }
.transition-colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.transition { .transition {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, -webkit-transform, -webkit-filter, -webkit-backdrop-filter;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
@ -2150,12 +2085,14 @@ video {
transition-duration: 150ms; transition-duration: 150ms;
} }
.ease-in-out { .transition-colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
} }
.\[a-zA-Z0-9\:_\] { .ease-in-out {
a-z-a--z0-9: ; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
} }
.\[key\:string\] { .\[key\:string\] {
@ -2166,6 +2103,10 @@ video {
_: string; _: string;
} }
.\[a-zA-Z0-9\:_\] {
a-z-a--z0-9: ;
}
:root { :root {
/* /*
* The main colour scheme of mapcomplete is configured here. * The main colour scheme of mapcomplete is configured here.
@ -2304,7 +2245,29 @@ input[type=text] {
* This very important section defines what the various input elements look like within the 'low-interaction' and 'interactive'-blocks * This very important section defines what the various input elements look like within the 'low-interaction' and 'interactive'-blocks
*/ */
button.small, .button.small {
line-height: 1rem;
margin: 0;
margin-left: 0.5rem;
padding: 0.25rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
height: -webkit-fit-content;
height: -moz-fit-content;
height: fit-content;
font-size: unset;
border: 2px solid var(--button-background);
border-radius: 0.5rem;
font-weight: normal;
transition: all 250ms;
--tw-text-opacity: 1;
--tw-bg-opacity: 1;
background: var(--low-interaction-background);
color: var(--low-interaction-foreground);
}
button, .button { button, .button {
align-items: center;
display: inline-flex; display: inline-flex;
line-height: 1.25rem; line-height: 1.25rem;
margin: 0.2rem; margin: 0.2rem;
@ -2313,7 +2276,6 @@ button, .button {
padding-right: 0.6rem; padding-right: 0.6rem;
font-size: large; font-size: large;
font-weight: bold; font-weight: bold;
/*-- invisible border: rendered on hover*/
border: 2px solid var(--button-background); border: 2px solid var(--button-background);
border-radius: 0.5rem; border-radius: 0.5rem;
transition: all 250ms; transition: all 250ms;
@ -2327,21 +2289,6 @@ button, .button {
box-shadow: 0 5px 10px #88888888; box-shadow: 0 5px 10px #88888888;
} }
button.small, .button.small {
line-height: 1rem;
margin: 0;
padding: 0.1rem;
font-size: unset;
/*-- invisible border: rendered on hover*/
border: 2px solid var(--low-interaction-background);
border-radius: 0.1rem;
transition: all 250ms;
--tw-text-opacity: 1;
--tw-bg-opacity: 1;
background: var(--low-interaction-background);
color: var(--low-interaction-foreground);
}
button.selected, .button.selected { button.selected, .button.selected {
background-color: var(--catch-detail-color); background-color: var(--catch-detail-color);
border-color: var(--catch-detail-color); border-color: var(--catch-detail-color);
@ -2754,10 +2701,6 @@ a.link-underline {
} }
@media (min-width: 640px) { @media (min-width: 640px) {
.sm\:top-3 {
top: 0.75rem;
}
.sm\:m-2 { .sm\:m-2 {
margin: 0.5rem; margin: 0.5rem;
} }
@ -2796,40 +2739,18 @@ a.link-underline {
height: 6rem; height: 6rem;
} }
.sm\:w-fit {
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.sm\:w-24 { .sm\:w-24 {
width: 6rem; width: 6rem;
} }
.sm\:max-w-sm {
max-width: 24rem;
}
.sm\:max-w-xl { .sm\:max-w-xl {
max-width: 36rem; max-width: 36rem;
} }
.sm\:flex-row {
flex-direction: row;
}
.sm\:flex-wrap {
flex-wrap: wrap;
}
.sm\:flex-nowrap { .sm\:flex-nowrap {
flex-wrap: nowrap; flex-wrap: nowrap;
} }
.sm\:items-start {
align-items: flex-start;
}
.sm\:items-stretch { .sm\:items-stretch {
align-items: stretch; align-items: stretch;
} }
@ -2850,10 +2771,6 @@ a.link-underline {
padding: 0.5rem; padding: 0.5rem;
} }
.sm\:pl-0 {
padding-left: 0px;
}
.sm\:pt-1 { .sm\:pt-1 {
padding-top: 0.25rem; padding-top: 0.25rem;
} }
@ -2919,10 +2836,6 @@ a.link-underline {
width: 2rem; width: 2rem;
} }
.md\:w-1\/3 {
width: 33.333333%;
}
.md\:w-6\/12 { .md\:w-6\/12 {
width: 50%; width: 50%;
} }

View file

@ -5,6 +5,7 @@ import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts" import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
import { ConfigMeta } from "../src/UI/Studio/configMeta" import { ConfigMeta } from "../src/UI/Studio/configMeta"
import { Utils } from "../src/Utils" import { Utils } from "../src/Utils"
import Validators from "../src/UI/InputElement/Validators"
const metainfo = { const metainfo = {
type: "One of the inputValidator types", type: "One of the inputValidator types",
@ -21,6 +22,16 @@ const metainfo = {
suggestions: "a javascript expression generating mappings", suggestions: "a javascript expression generating mappings",
} }
/**
* Applies 'onEach' on every leaf of the JSONSchema
* @param onEach
* @param scheme
* @param fullScheme
* @param path
* @param isHandlingReference
* @param required
* @constructor
*/
function WalkScheme<T>( function WalkScheme<T>(
onEach: (schemePart: JsonSchema, path: string[]) => T, onEach: (schemePart: JsonSchema, path: string[]) => T,
scheme: JsonSchema, scheme: JsonSchema,
@ -45,10 +56,15 @@ function WalkScheme<T>(
// We abort here to avoid infinite recursion // We abort here to avoid infinite recursion
return [] return []
} }
// The 'scheme' might contain some extra info, such as 'description'
// This effectively overwrites properties from the loaded scheme
const loadedScheme = fullScheme.definitions[definitionName] const loadedScheme = fullScheme.definitions[definitionName]
const syntheticScheme = { ...loadedScheme, ...scheme }
syntheticScheme["child-description"] = loadedScheme.description
delete syntheticScheme["$ref"]
return WalkScheme( return WalkScheme(
onEach, onEach,
loadedScheme, syntheticScheme,
fullScheme, fullScheme,
path, path,
[...isHandlingReference, definitionName], [...isHandlingReference, definitionName],
@ -111,65 +127,106 @@ function WalkScheme<T>(
return results return results
} }
function extractHintsFrom(
description: string,
fieldnames: string[],
path: (string | number)[],
type: any
): Record<string, string> {
if (!description) {
return {}
}
const hints = {}
const lines = description.split("\n")
for (const fieldname of fieldnames) {
const hintIndex = lines.findIndex((line) =>
line
.trim()
.toLocaleLowerCase()
.startsWith(fieldname + ":")
)
if (hintIndex < 0) {
continue
}
const hintLine = lines[hintIndex].substring((fieldname + ":").length).trim()
if (fieldname === "type") {
hints["typehint"] = hintLine
} else {
hints[fieldname] = hintLine
}
}
if (hints["types"]) {
const numberOfExpectedSubtypes = hints["types"].replaceAll("|", ";").split(";").length
if (!Array.isArray(type)) {
throw (
"At " +
path.join(".") +
"Invalid hint in the documentation: `types` indicates that there are " +
numberOfExpectedSubtypes +
" subtypes, but object does not support subtypes. Did you mean `type` instead?\n\tTypes are: " +
hints["types"]
)
}
const numberOfActualTypes = type.length
if (numberOfActualTypes !== numberOfExpectedSubtypes) {
throw `At ${path.join(
"."
)}\nInvalid hint in the documentation: \`types\` indicates that there are ${numberOfExpectedSubtypes} subtypes, but there are ${numberOfActualTypes} subtypes
\tTypes are: ${hints["types"]}`
}
}
if (hints["suggestions"]) {
const suggestions = hints["suggestions"]
const f = new Function("{ layers, themes, validators }", suggestions)
hints["suggestions"] = f({
layers: AllSharedLayers.sharedLayers,
themes: AllKnownLayouts.allKnownLayouts,
validators: Validators,
})
}
return hints
}
/**
* Extracts the 'configMeta' from the given schema, based on attributes in the description
* @param fieldnames
* @param fullSchema
*/
function addMetafields(fieldnames: string[], fullSchema: JsonSchema): ConfigMeta[] { function addMetafields(fieldnames: string[], fullSchema: JsonSchema): ConfigMeta[] {
const fieldNamesSet = new Set(fieldnames)
const onEach = (schemePart, path) => { const onEach = (schemePart, path) => {
if (schemePart.description === undefined) { if (schemePart.description === undefined) {
return return
} }
if (path.length === 2 && path[0] === "mappings" && path[1] === "if") {
console.log("HI")
}
const type = schemePart.items?.anyOf ?? schemePart.type ?? schemePart.anyOf const type = schemePart.items?.anyOf ?? schemePart.type ?? schemePart.anyOf
const hints = {} let description = schemePart.description
let description = schemePart.description.split("\n")
for (const fieldname of fieldnames) { let hints = extractHintsFrom(description, fieldnames, path, type)
const hintIndex = description.findIndex((line) => const childDescription = schemePart["child-description"]
line if (childDescription) {
.trim() const childHints = extractHintsFrom(childDescription, fieldnames, path, type)
.toLocaleLowerCase() hints = { ...childHints, ...hints }
.startsWith(fieldname + ":") description = description ?? childDescription
) }
if (hintIndex < 0) {
const cleanedDescription: string[] = []
for (const line of description.split("\n")) {
const keyword = line.split(":").at(0).trim().toLowerCase()
if (fieldNamesSet.has(keyword)) {
continue continue
} }
const hintLine = description[hintIndex].substring((fieldname + ":").length).trim() cleanedDescription.push(line)
description.splice(hintIndex, 1)
if (fieldname === "type") {
hints["typehint"] = hintLine
} else {
hints[fieldname] = hintLine
}
} }
return {
if (hints["types"]) { hints,
const numberOfExpectedSubtypes = hints["types"].replaceAll("|", ";").split(";").length type,
if (!Array.isArray(type)) { description: cleanedDescription.join("\n"),
throw (
"At " +
path.join(".") +
"Invalid hint in the documentation: `types` indicates that there are " +
numberOfExpectedSubtypes +
" subtypes, but object does not support subtypes. Did you mean `type` instead?\n\tTypes are: " +
hints["types"]
)
}
const numberOfActualTypes = type.length
if (numberOfActualTypes !== numberOfExpectedSubtypes) {
throw `At ${path.join(
"."
)}\nInvalid hint in the documentation: \`types\` indicates that there are ${numberOfExpectedSubtypes} subtypes, but there are ${numberOfActualTypes} subtypes
\tTypes are: ${hints["types"]}`
}
} }
if (hints["suggestions"]) {
const suggestions = hints["suggestions"]
console.log("Creating suggestions for expression", suggestions)
const f = new Function("{ layers, themes }", suggestions)
hints["suggestions"] = f({
layers: AllSharedLayers.sharedLayers,
themes: AllKnownLayouts.allKnownLayouts,
})
}
return { hints, type, description: description.join("\n") }
} }
return WalkScheme(onEach, fullSchema, fullSchema, [], [], fullSchema.required).map( return WalkScheme(onEach, fullSchema, fullSchema, [], [], fullSchema.required).map(
@ -209,8 +266,6 @@ function substituteReferences(
path.type[i] = target path.type[i] = target
continue continue
} }
console.log("Expanding " + name)
} }
} }
} }
@ -236,10 +291,10 @@ function validateMeta(path: ConfigMeta): string | undefined {
return undefined return undefined
} }
if (path.hints.question === undefined && !Array.isArray(path.type)) { if (path.hints.question === undefined && !Array.isArray(path.type)) {
return ( /* return (
ctx + ctx +
" does not have a question set. As such, MapComplete-studio users will not be able to set this property" " does not have a question set. As such, MapComplete-studio users will not be able to set this property"
) )//*/
} }
return undefined return undefined
@ -250,18 +305,19 @@ function extractMeta(
path: string, path: string,
allDefinitions: Record<string, JsonSchema> allDefinitions: Record<string, JsonSchema>
): string[] { ): string[] {
let themeSchema: JsonSchema = JSON.parse( const schema: JsonSchema = JSON.parse(
readFileSync("./Docs/Schemas/" + typename + ".schema.json", { encoding: "utf8" }) readFileSync("./Docs/Schemas/" + typename + ".schema.json", { encoding: "utf8" })
) )
const metakeys = Array.from(Object.keys(metainfo)) const metakeys = Array.from(Object.keys(metainfo)).map((s) => s.toLowerCase())
const paths = addMetafields(metakeys, themeSchema) const paths = addMetafields(metakeys, schema)
substituteReferences(paths, themeSchema, allDefinitions) substituteReferences(paths, schema, allDefinitions)
writeFileSync("./src/assets/" + path + ".json", JSON.stringify(paths, null, " ")) const fullPath = "./src/assets/schemas/" + path + ".json"
console.log("Written meta to ./assets/" + path) writeFileSync(fullPath, JSON.stringify(paths, null, " "))
console.log("Written meta to " + fullPath)
return Utils.NoNull(paths.map((p) => validateMeta(p))) return Utils.NoNull(paths.map((p) => validateMeta(p)))
} }
@ -290,15 +346,17 @@ function main() {
encoding: "utf8", encoding: "utf8",
}) })
} }
const errs = extractMeta("LayerConfigJson", "layerconfigmeta", allDefinitions) const errs: string[] = []
extractMeta("LayoutConfigJson", "layoutconfigmeta", allDefinitions) // errs = extractMeta("LayerConfigJson", "layerconfigmeta", allDefinitions)
extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta", allDefinitions) // errs.push(...extractMeta("LayoutConfigJson", "layoutconfigmeta", allDefinitions))
extractMeta( // errs.push(...extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta", allDefinitions))
"QuestionableTagRenderingConfigJson", errs.push(
"questionabletagrenderingconfigmeta", ...extractMeta(
allDefinitions "QuestionableTagRenderingConfigJson",
"questionabletagrenderingconfigmeta",
allDefinitions
)
) )
if (errs.length > 0) { if (errs.length > 0) {
for (const err of errs) { for (const err of errs) {
console.error(err) console.error(err)

View file

@ -1,21 +1,27 @@
import { TagConfigJson } from "./TagConfigJson" import { TagConfigJson } from "./TagConfigJson"
import { TagRenderingConfigJson } from "./TagRenderingConfigJson" import { TagRenderingConfigJson } from "./TagRenderingConfigJson"
import { Translatable } from "./Translatable"
export interface MappingConfigJson { export interface MappingConfigJson {
/** /**
* quesiton: What tags should be matched to show this option? * question: What tags should be matched to show this option?
* *
* If in 'question'-mode and the contributor selects this option, these tags will be applied to the object * If in 'question'-mode and the contributor selects this option, these tags will be applied to the object
*/ */
if: TagConfigJson if: TagConfigJson
/** /**
* Shown if the 'if is fulfilled * Question: What corresponding text should be shown?
* Shown if the `if` is fulfilled
* Type: rendered * Type: rendered
*/ */
then: string | Record<string, string> then: string | Record<string, string>
/** /**
* An extra icon supporting the choice * question: What icon should be shown next to this mapping?
*
* This icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)
*
* ifunset: Show no icon
* Type: icon * Type: icon
*/ */
icon?: icon?:
@ -33,6 +39,11 @@ export interface MappingConfigJson {
} }
/** /**
* question: Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?
* iftrue: Never show this mapping as option to pick
* ifunset: Always show this mapping as option to pick
* type: tag
*
* In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation). * In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).
* *
* In the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user. * In the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.
@ -93,7 +104,10 @@ export interface MappingConfigJson {
* } * }
*/ */
hideInAnswer?: boolean | TagConfigJson hideInAnswer?: boolean | TagConfigJson
/** /**
* question: What tags should be applied if this mapping is _not_ chosen?
*
* Only applicable if 'multiAnswer' is set. * Only applicable if 'multiAnswer' is set.
* This is for situations such as: * This is for situations such as:
* `accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected. * `accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.
@ -104,7 +118,10 @@ export interface MappingConfigJson {
ifnot?: TagConfigJson ifnot?: TagConfigJson
/** /**
* If chosen as answer, these tags will be applied as well onto the object. * question: What extra tags should be added to the object if this object is chosen?
* type: simple_tag[]
*
* If chosen as answer, these tags will be applied onto the object, together with the tags from the `if`
* Not compatible with multiAnswer. * Not compatible with multiAnswer.
* *
* This can be used e.g. to erase other keys which indicate the 'not' value: * This can be used e.g. to erase other keys which indicate the 'not' value:
@ -120,21 +137,25 @@ export interface MappingConfigJson {
addExtraTags?: string[] addExtraTags?: string[]
/** /**
* question: If there are many options, what search terms match too?
* If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction * If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction
* *
* Searchterms (per language) allow to easily find an option if there are many options * Searchterms (per language) allow to easily find an option if there are many options
* group: hidden
*/ */
searchTerms?: Record<string, string[]> searchTerms?: Record<string, string[]>
/** /**
* If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden * If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden
* Use this sparingly * Use this sparingly
* group: hidden
*/ */
priorityIf?: TagConfigJson priorityIf?: TagConfigJson
/** /**
* Used for comments or to disable a validation * Used for comments or to disable a validation
* *
* group: hidden
* ignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed * ignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed
*/ */
"#"?: string | "ignore-image-in-then" "#"?: string | "ignore-image-in-then"
@ -145,7 +166,7 @@ export interface MappingConfigJson {
* If the desired tags are missing and a question is defined, a question will be shown instead. * If the desired tags are missing and a question is defined, a question will be shown instead.
*/ */
export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJson { export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJson {
/** /*
* The id of the tagrendering, should be an unique string. * The id of the tagrendering, should be an unique string.
* Used to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise. * Used to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.
* *
@ -176,7 +197,8 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
*/ */
freeform?: { freeform?: {
/** /**
* @inheritDoc * question What is the name of the attribute that should be written to?
* ifunset: do not offer a freeform textfield as answer option
*/ */
key: string key: string
@ -184,6 +206,7 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
* question: What is the input type? * question: What is the input type?
* The type of the text-field, e.g. 'string', 'nat', 'float', 'date',... * The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...
* See Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values * See Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values
* suggestions: return validators.AllValidators.filter(type => !type.isMeta).map((type) => ({if: "value="+type.name, then: "<b>"+type.name+"</b> "+type.explanation.split("\n")[0]}))
*/ */
type?: string type?: string
/** /**
@ -203,11 +226,12 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
addExtraTags?: string[] addExtraTags?: string[]
/** /**
* When set, influences the way a question is asked. * question: Show the freeform as box within the question?
* Instead of showing a full-width text field, the text field will be shown within the rendering of the question. * Instead of showing a full-width text field, the text field will be shown within the rendering of the question.
* *
* This combines badly with special input elements, as it'll distort the layout. * This combines badly with special input elements, as it'll distort the layout.
* Note that this will be set automatically if no special elements are present. * ifunset: show the freeform input field full-width
* iftrue: show the freeform input field as a small field within the question
*/ */
inline?: boolean inline?: boolean
@ -219,16 +243,21 @@ export interface QuestionableTagRenderingConfigJson extends TagRenderingConfigJs
} }
/** /**
* If it turns out that this tagRendering doesn't match _any_ value, then we show this question. * question: What question should be shown to the contributor?
* If undefined, the question is never asked and this tagrendering is read-only *
* A question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.
*
* ifunset: This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering
*/ */
question?: string | Record<string, string> question?: string | Translatable
/** /**
* A hint which is shown in subtle text under the question. * question: Should some extra information be shown to the contributor, alongside the question?
* This hint is shown in subtle text under the question.
* This can give some extra information on what the answer should ook like * This can give some extra information on what the answer should ook like
* ifunset: No extra hint is given
*/ */
questionHint?: string | Record<string, string> questionHint?: string | Translatable
/** /**
* A list of labels. These are strings that are used for various purposes, e.g. to filter them away * A list of labels. These are strings that are used for various purposes, e.g. to filter them away

View file

@ -138,6 +138,7 @@ export interface TagRenderingConfigJson {
/** /**
* question: What icon should be added to this mapping? * question: What icon should be added to this mapping?
* An icon supporting this mapping; typically shown pretty small * An icon supporting this mapping; typically shown pretty small
* inline: <img src='{icon}' class="w-8 h-8" /> {icon}
* Type: icon * Type: icon
*/ */
icon?: icon?:

View file

@ -150,7 +150,9 @@ export default class TagRenderingConfig {
json.freeform.type && json.freeform.type &&
Validators.availableTypes.indexOf(<any>json.freeform.type) < 0 Validators.availableTypes.indexOf(<any>json.freeform.type) < 0
) { ) {
throw `At ${context}: invalid type, perhaps you meant ${Utils.sortedByLevenshteinDistance( throw `At ${context}: invalid type ${
json.freeform.type
}, perhaps you meant ${Utils.sortedByLevenshteinDistance(
json.freeform.key, json.freeform.key,
<any>Validators.availableTypes, <any>Validators.availableTypes,
(s) => <any>s (s) => <any>s

View file

@ -0,0 +1,20 @@
<script lang="ts">/**
* Input helper to create a tag. The tag is JSON-encoded
*/
import { UIEventSource } from "../../../Logic/UIEventSource";
import BasicTagInput from "../../Studio/TagInput/BasicTagInput.svelte";
export let value: UIEventSource<undefined | string>;
export let uploadableOnly: boolean;
export let overpassSupportNeeded: boolean;
/**
* Only show the taginfo-statistics if they are suspicious (thus: less then 250 entries)
*/
export let silent: boolean = false;
</script>
<BasicTagInput {overpassSupportNeeded} {silent} tag={value} {uploadableOnly} />

View file

@ -0,0 +1,33 @@
<script lang="ts">/**
* Input helper to create a tag. The tag is JSON-encoded
*/
import { UIEventSource } from "../../../Logic/UIEventSource";
import type { TagConfigJson } from "../../../Models/ThemeConfig/Json/TagConfigJson";
import FullTagInput from "../../Studio/TagInput/FullTagInput.svelte";
export let value: UIEventSource<undefined | string>;
export let uploadableOnly: boolean;
export let overpassSupportNeeded: boolean;
/**
* Only show the taginfo-statistics if they are suspicious (thus: less then 250 entries)
*/
export let silent: boolean = false;
let tag: UIEventSource<string | TagConfigJson> = value.sync(s => {
try {
return JSON.parse(s);
} catch (e) {
return s;
}
}, [], t => {
if(typeof t === "string"){
return t
}
return JSON.stringify(t);
});
</script>
<FullTagInput {overpassSupportNeeded} {silent} {tag} {uploadableOnly} />

View file

@ -15,6 +15,8 @@ import { Feature } from "geojson"
import { GeoOperations } from "../../Logic/GeoOperations" import { GeoOperations } from "../../Logic/GeoOperations"
import ImageHelper from "./Helpers/ImageHelper.svelte" import ImageHelper from "./Helpers/ImageHelper.svelte"
import TranslationInput from "./Helpers/TranslationInput.svelte" import TranslationInput from "./Helpers/TranslationInput.svelte"
import TagInput from "./Helpers/TagInput.svelte"
import SimpleTagInput from "./Helpers/SimpleTagInput.svelte"
export interface InputHelperProperties { export interface InputHelperProperties {
/** /**
@ -59,9 +61,11 @@ export default class InputHelpers {
wikidata: InputHelpers.constructWikidataHelper, wikidata: InputHelpers.constructWikidataHelper,
image: (value) => new SvelteUIElement(ImageHelper, { value }), image: (value) => new SvelteUIElement(ImageHelper, { value }),
translation: (value) => new SvelteUIElement(TranslationInput, { value }), translation: (value) => new SvelteUIElement(TranslationInput, { value }),
tag: (value) => new SvelteUIElement(TagInput, { value }),
simple_tag: (value) => new SvelteUIElement(SimpleTagInput, { value }),
} as const } as const
public static hideInputField : string[] = ["translation"] public static hideInputField: string[] = ["translation", "simple_tag", "tag"]
/** /**
* Constructs a mapProperties-object for the given properties. * Constructs a mapProperties-object for the given properties.

View file

@ -1,6 +1,6 @@
import BaseUIElement from "../BaseUIElement"; import BaseUIElement from "../BaseUIElement"
import { Translation } from "../i18n/Translation"; import { Translation } from "../i18n/Translation"
import Translations from "../i18n/Translations"; import Translations from "../i18n/Translations"
/** /**
* A 'TextFieldValidator' contains various methods to check and cleanup an entered value or to give feedback. * A 'TextFieldValidator' contains various methods to check and cleanup an entered value or to give feedback.
@ -16,13 +16,23 @@ export abstract class Validator {
/** /**
* What HTML-inputmode to use * What HTML-inputmode to use
*/ */
public readonly inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search' public readonly inputmode?:
| "none"
| "text"
| "tel"
| "url"
| "email"
| "numeric"
| "decimal"
| "search"
public readonly textArea: boolean public readonly textArea: boolean
public readonly isMeta?: boolean
constructor( constructor(
name: string, name: string,
explanation: string | BaseUIElement, explanation: string | BaseUIElement,
inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search', inputmode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search",
textArea?: false | boolean textArea?: false | boolean
) { ) {
this.name = name this.name = name

View file

@ -23,6 +23,8 @@ import ImageUrlValidator from "./Validators/ImageUrlValidator"
import TagKeyValidator from "./Validators/TagKeyValidator" import TagKeyValidator from "./Validators/TagKeyValidator"
import TranslationValidator from "./Validators/TranslationValidator" import TranslationValidator from "./Validators/TranslationValidator"
import FediverseValidator from "./Validators/FediverseValidator" import FediverseValidator from "./Validators/FediverseValidator"
import IconValidator from "./Validators/IconValidator"
import TagValidator from "./Validators/TagValidator"
export type ValidatorType = (typeof Validators.availableTypes)[number] export type ValidatorType = (typeof Validators.availableTypes)[number]
@ -48,7 +50,9 @@ export default class Validators {
"simple_tag", "simple_tag",
"key", "key",
"translation", "translation",
"icon",
"fediverse", "fediverse",
"tag",
] as const ] as const
public static readonly AllValidators: ReadonlyArray<Validator> = [ public static readonly AllValidators: ReadonlyArray<Validator> = [
@ -70,20 +74,15 @@ export default class Validators {
new ColorValidator(), new ColorValidator(),
new ImageUrlValidator(), new ImageUrlValidator(),
new SimpleTagValidator(), new SimpleTagValidator(),
new TagValidator(),
new TagKeyValidator(), new TagKeyValidator(),
new TranslationValidator(), new TranslationValidator(),
new IconValidator(),
new FediverseValidator(), new FediverseValidator(),
] ]
private static _byType = Validators._byTypeConstructor() private static _byType = Validators._byTypeConstructor()
private static _byTypeConstructor(): Map<ValidatorType, Validator> {
const map = new Map<ValidatorType, Validator>()
for (const validator of Validators.AllValidators) {
map.set(<ValidatorType>validator.name, validator)
}
return map
}
public static HelpText(): BaseUIElement { public static HelpText(): BaseUIElement {
const explanations: BaseUIElement[] = Validators.AllValidators.map((type) => const explanations: BaseUIElement[] = Validators.AllValidators.map((type) =>
new Combine([new Title(type.name, 3), type.explanation]).SetClass("flex flex-col") new Combine([new Title(type.name, 3), type.explanation]).SetClass("flex flex-col")
@ -95,6 +94,14 @@ export default class Validators {
]).SetClass("flex flex-col") ]).SetClass("flex flex-col")
} }
private static _byTypeConstructor(): Map<ValidatorType, Validator> {
const map = new Map<ValidatorType, Validator>()
for (const validator of Validators.AllValidators) {
map.set(<ValidatorType>validator.name, validator)
}
return map
}
static get(type: ValidatorType): Validator { static get(type: ValidatorType): Validator {
return Validators._byType.get(type) return Validators._byType.get(type)
} }

View file

@ -0,0 +1,46 @@
import { Validator } from "../Validator"
import { Translation } from "../../i18n/Translation"
import licenses from "../../../assets/generated/license_info.json"
import { Utils } from "../../../Utils"
export default class IconValidator extends Validator {
private static allLicenses = new Set(licenses.map((l) => l.path))
private static allLicensesArr = Array.from(IconValidator.allLicenses)
public static readonly isMeta = true
constructor() {
super("icon", "Makes sure that a valid .svg-path is added")
}
getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined {
if (!s.startsWith("http")) {
if (!IconValidator.allLicenses.has(s)) {
const close = sloppy
? []
: Utils.sortedByLevenshteinDistance(
s.substring(s.lastIndexOf("/")),
IconValidator.allLicensesArr,
(s) => s.substring(s.lastIndexOf("/"))
).slice(0, 5)
return new Translation(
[
`Unkown builtin icon ${s}, perhaps you meant one of: <ul>`,
...close.map(
(item) =>
`<li><span class="flex justify-start"> <img src='${item}' class="w-6 h-6"/>${item}</span></li>`
),
"</ul>",
].join("")
)
}
}
if (!s.endsWith(".svg")) {
return new Translation("An icon should end with `.svg`")
}
return undefined
}
isValid(key: string, getCountry?: () => string): boolean {
return this.getFeedback(key, getCountry, true) === undefined
}
}

View file

@ -3,6 +3,7 @@ import { Translation } from "../../i18n/Translation"
export default class ImageUrlValidator extends UrlValidator { export default class ImageUrlValidator extends UrlValidator {
private static readonly allowedExtensions = ["jpg", "jpeg", "svg", "png"] private static readonly allowedExtensions = ["jpg", "jpeg", "svg", "png"]
public readonly isMeta = true
constructor() { constructor() {
super( super(

View file

@ -8,6 +8,8 @@ import TagKeyValidator from "./TagKeyValidator"
*/ */
export default class SimpleTagValidator extends Validator { export default class SimpleTagValidator extends Validator {
private static readonly KeyValidator = new TagKeyValidator() private static readonly KeyValidator = new TagKeyValidator()
public readonly isMeta = true
constructor() { constructor() {
super( super(
"simple_tag", "simple_tag",

View file

@ -3,6 +3,8 @@ import { Translation } from "../../i18n/Translation"
import Translations from "../../i18n/Translations" import Translations from "../../i18n/Translations"
export default class TagKeyValidator extends Validator { export default class TagKeyValidator extends Validator {
public readonly isMeta = true
constructor() { constructor() {
super("key", "Validates a key, mostly that no weird characters are used") super("key", "Validates a key, mostly that no weird characters are used")
} }

View file

@ -0,0 +1,24 @@
import { Validator } from "../Validator"
import { Translation } from "../../i18n/Translation"
import Translations from "../../i18n/Translations"
import TagKeyValidator from "./TagKeyValidator"
import SimpleTagValidator from "./SimpleTagValidator"
/**
* Checks that the input conforms a JSON-encoded tag expression or a simpleTag`key=value`,
*/
export default class TagValidator extends Validator {
public readonly isMeta = true
constructor() {
super("tag", "A simple tag of the format `key=value` OR a tagExpression")
}
getFeedback(tag: string, _): Translation | undefined {
return undefined
}
isValid(tag: string, _): boolean {
return this.getFeedback(tag, _) === undefined
}
}

View file

@ -1,6 +1,8 @@
import { Validator } from "../Validator" import { Validator } from "../Validator"
export default class TranslationValidator extends Validator { export default class TranslationValidator extends Validator {
public readonly isMeta = true
constructor() { constructor() {
super("translation", "Makes sure the the string is of format `Record<string, string>` ") super("translation", "Makes sure the the string is of format `Record<string, string>` ")
} }

View file

@ -29,7 +29,7 @@
}) })
) )
let htmlElem: HTMLBaseElement let htmlElem: HTMLDivElement
$: { $: {
if (editMode && htmlElem !== undefined) { if (editMode && htmlElem !== undefined) {
// EditMode switched to true, so the person wants to make a change // EditMode switched to true, so the person wants to make a change
@ -37,7 +37,7 @@
// Some delay is applied to give Svelte the time to render the _question_ // Some delay is applied to give Svelte the time to render the _question_
window.setTimeout(() => { window.setTimeout(() => {
Utils.scrollIntoView(htmlElem) Utils.scrollIntoView(<any> htmlElem)
}, 50) }, 50)
} }
} }

View file

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import EditLayerState from "./EditLayerState"; import EditLayerState from "./EditLayerState";
import layerSchemaRaw from "../../assets/layerconfigmeta.json" import layerSchemaRaw from "../../assets/schemas/layerconfigmeta.json"
import Region from "./Region.svelte"; import Region from "./Region.svelte";
import TabbedGroup from "../Base/TabbedGroup.svelte"; import TabbedGroup from "../Base/TabbedGroup.svelte";
import {UIEventSource} from "../../Logic/UIEventSource"; import {UIEventSource} from "../../Logic/UIEventSource";
@ -10,7 +10,7 @@
import drinking_water from "../../../assets/layers/drinking_water/drinking_water.json" import drinking_water from "../../../assets/layers/drinking_water/drinking_water.json"
const layerSchema: ConfigMeta[] = layerSchemaRaw const layerSchema: ConfigMeta[] = <any> layerSchemaRaw
let state = new EditLayerState(layerSchema) let state = new EditLayerState(layerSchema)
state.configuration.setData(drinking_water) state.configuration.setData(drinking_water)
/** /**
@ -40,14 +40,13 @@
<TabbedGroup tab={new UIEventSource(1)}> <TabbedGroup tab={new UIEventSource(1)}>
<div slot="title0">General properties</div> <div slot="title0">General properties</div>
<div class="flex flex-col" slot="content0"> <div class="flex flex-col" slot="content0">
<!--
{#each baselayerRegions as region} {#each baselayerRegions as region}
<Region {state} configs={perRegion[region]} title={region}/> <Region {state} configs={perRegion[region]} title={region}/>
{/each} {/each}
{#each leftoverRegions as region} {#each leftoverRegions as region}
<Region {state} configs={perRegion[region]} title={region}/> <Region {state} configs={perRegion[region]} title={region}/>
{/each}--> {/each}
</div> </div>
<div slot="title1">Information panel (questions and answers)</div> <div slot="title1">Information panel (questions and answers)</div>
@ -57,9 +56,8 @@
The bulk of the popup content The bulk of the popup content
</div> </div>
</Region> </Region>
<!--
<Region {state} configs={perRegion["title"]} title="Popup title"/> <Region {state} configs={perRegion["title"]} title="Popup title"/>
<Region {state} configs={perRegion["editing"]} title="Other editing elements"/>--> <Region {state} configs={perRegion["editing"]} title="Other editing elements"/>
</div> </div>
<div slot="title2">Rendering on the map</div> <div slot="title2">Rendering on the map</div>

View file

@ -2,8 +2,6 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
import { ConfigMeta } from "./configMeta" import { ConfigMeta } from "./configMeta"
import { Store, UIEventSource } from "../../Logic/UIEventSource" import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
import { DeleteConfigJson } from "../../Models/ThemeConfig/Json/DeleteConfigJson"
import { Utils } from "../../Utils"
export default class EditLayerState { export default class EditLayerState {
public readonly osmConnection: OsmConnection public readonly osmConnection: OsmConnection
@ -40,6 +38,15 @@ export default class EditLayerState {
return entry return entry
} }
public getStoreFor(path: ReadonlyArray<string | number>): UIEventSource<any | undefined> {
const store = new UIEventSource<any>(this.getCurrentValueFor(path))
store.addCallback((v) => {
console.log("UPdating store", path, v)
this.setValueAt(path, v)
})
return store
}
public register( public register(
path: ReadonlyArray<string | number>, path: ReadonlyArray<string | number>,
value: Store<any>, value: Store<any>,

View file

@ -0,0 +1,71 @@
<script lang="ts">
import type { MappingConfigJson } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import EditLayerState from "./EditLayerState";
import { Translation } from "../i18n/Translation";
import { UIEventSource } from "../../Logic/UIEventSource";
import type { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson";
import { TagUtils } from "../../Logic/Tags/TagUtils";
import FromHtml from "../Base/FromHtml.svelte";
import { PencilIcon } from "@rgossiaux/svelte-heroicons/outline";
import Region from "./Region.svelte";
import type { ConfigMeta } from "./configMeta";
import configs from "../../assets/schemas/questionabletagrenderingconfigmeta.json";
import { Utils } from "../../Utils";
export let mapping: MappingConfigJson;
export let state: EditLayerState;
export let path: (string | number)[];
let tag: UIEventSource<TagConfigJson> = state.getStoreFor([...path, "if"]);
let parsedTag = tag.map(t => t ? TagUtils.Tag(t) : undefined);
let exampleTags = parsedTag.map(pt => {
if (!pt) {
return {};
}
const keys = pt.usedKeys();
const o = {};
for (const key of keys) {
o[key] = "value";
}
return o;
});
let uploadableOnly: boolean = true;
let thenStringified = state.getStoreFor([...path, "then"]).sync(t => t ? JSON.stringify(t) : undefined, [], s => s ? JSON.parse(s) : undefined);
let thenParsed = thenStringified.map(s => s ? JSON.parse(s) : s);
let editMode = Object.keys(thenParsed.data).length === 0;
const mappingConfigs: ConfigMeta[] = configs.filter(c => c.path[0] === "mappings")
.map(c => <ConfigMeta>Utils.Clone(c))
.map(c => {
c.path.splice(0, 1);
return c;
})
.filter(c => c.path.length == 1 && c.hints.group !== "hidden");
</script>
<button on:click={() => {editMode = !editMode}}>
<PencilIcon class="w-6 h-6" />
</button>
{#if editMode}
<div class="flex justify-between items-start w-full">
<div class="flex flex-col w-full">
<Region {state} configs={mappingConfigs} path={path} />
</div>
<slot name="delete" />
</div>
{:else}
<div>
{#if Object.keys($thenParsed).length > 0}
<b>
{new Translation($thenParsed).txt}
</b>
{:else}
<i>No then is set</i>
{/if}
<FromHtml src={ $parsedTag?.asHumanString(false, false, $exampleTags)} />
</div>
{/if}

View file

@ -2,28 +2,32 @@
* A 'region' is a collection of properties that can be edited which are somewhat related. * A 'region' is a collection of properties that can be edited which are somewhat related.
* They will typically be a subset of some properties * They will typically be a subset of some properties
*/ */
import type {ConfigMeta} from "./configMeta"; import type { ConfigMeta } from "./configMeta";
import EditLayerState from "./EditLayerState"; import EditLayerState from "./EditLayerState";
import SchemaBasedInput from "./SchemaBasedInput.svelte"; import SchemaBasedInput from "./SchemaBasedInput.svelte";
export let state: EditLayerState export let state: EditLayerState;
export let configs: ConfigMeta[] export let configs: ConfigMeta[];
export let title: string export let title: string | undefined = undefined;
export let path: (string | number)[] = [];
</script> </script>
{#if title} {#if title}
<div class="w-full flex flex-col">
<h3>{title}</h3> <h3>{title}</h3>
<div class="pl-2 border border-black flex flex-col gap-y-1"> <div class="pl-2 border border-black flex flex-col gap-y-1 w-full">
<slot name="description"/> <slot name="description" />
{#each configs as config} {#each configs as config}
<SchemaBasedInput {state} path={config.path} schema={config}/> <SchemaBasedInput {state} path={config.path} schema={config} />
{/each} {/each}
</div> </div>
</div>
{:else} {:else}
<div class="pl-2 flex flex-col gap-y-1"> <div class="pl-2 flex flex-col gap-y-1 w-full">
{#each configs as config} {#each configs as config}
<SchemaBasedInput {state} path={config.path} schema={config}/> <SchemaBasedInput {state} path={path.concat(config.path)} schema={config} />
{/each} {/each}
</div> </div>
{/if} {/if}

View file

@ -2,7 +2,7 @@
import EditLayerState from "./EditLayerState"; import EditLayerState from "./EditLayerState";
import {UIEventSource} from "../../Logic/UIEventSource"; import {UIEventSource} from "../../Logic/UIEventSource";
import type {TagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson"; import type {TagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson";
import TagInput from "./TagInput/TagInput.svelte"; import FullTagInput from "./TagInput/FullTagInput.svelte";
import type {ConfigMeta} from "./configMeta"; import type {ConfigMeta} from "./configMeta";
import {PencilAltIcon} from "@rgossiaux/svelte-heroicons/solid"; import {PencilAltIcon} from "@rgossiaux/svelte-heroicons/solid";
import { onDestroy } from "svelte"; import { onDestroy } from "svelte";
@ -40,13 +40,14 @@
<div class="interactive border-interactive"> <div class="interactive border-interactive">
<h3>{schema.hints.question ?? "What tags should be applied?"}</h3> <h3>{schema.hints.question ?? "What tags should be applied?"}</h3>
{schema.description} {schema.description}
<TagInput {tag}/> <FullTagInput {tag}/>
<div class="flex justify-end"> <div class="flex justify-end">
<button class="primary w-fit" on:click={() => {mode = "set"}}> <button class="primary w-fit" on:click={() => {mode = "set"}}>
Save Save
</button> </button>
</div> </div>
<div class="subtle">RegisteredTagInput based on schema: {JSON.stringify(schema)}</div>
</div> </div>
{:else} {:else}
<div class="low-interaction flex justify-between"> <div class="low-interaction flex justify-between">

View file

@ -10,16 +10,18 @@
export let state: EditLayerState; export let state: EditLayerState;
export let schema: ConfigMeta; export let schema: ConfigMeta;
let title = schema.path.at(-1); let title = schema.path.at(-1);
let singular = title; let singular = title;
if (title.endsWith("s")) { if (title?.endsWith("s")) {
singular = title.slice(0, title.length - 1); singular = title.slice(0, title.length - 1);
} }
let article = "a"; let article = "a";
if (singular.match(/^[aeoui]/)) { if (singular?.match(/^[aeoui]/)) {
article = "an"; article = "an";
} }
export let path: (string | number)[] = []; export let path: (string | number)[] = [];
const isTagRenderingBlock = path.length === 1 && path[0] === "tagRenderings";
const subparts = state.getSchemaStartingWith(schema.path); const subparts = state.getSchemaStartingWith(schema.path);
@ -39,8 +41,11 @@
let createdItems = values.data.length; let createdItems = values.data.length;
function createItem() { function createItem(valueToSet?: any) {
values.data.push(createdItems); values.data.push(createdItems);
if (valueToSet) {
state.setValueAt([...path, createdItems], valueToSet);
}
createdItems++; createdItems++;
values.ping(); values.ping();
} }
@ -87,16 +92,24 @@
{/each} {/each}
{:else} {:else}
{#each $values as value (value)} {#each $values as value (value)}
<div class="flex justify-between items-center">
<h3 class="m-0">{singular} {value}</h3> {#if !isTagRenderingBlock}
<button class="border-black border rounded-full p-1 w-fit h-fit" <div class="flex justify-between items-center">
on:click={() => {del(value)}}> <h3 class="m-0">{singular} {value}</h3>
<TrashIcon class="w-4 h-4" /> <button class="border-black border rounded-full p-1 w-fit h-fit"
</button> on:click={() => {del(value)}}>
</div> <TrashIcon class="w-4 h-4" />
</button>
</div>
{/if}
<div class="border border-black"> <div class="border border-black">
{#if path.length === 1 && path[0] === "tagRenderings"} {#if isTagRenderingBlock}
<TagRenderingInput path={path.concat(value)} {state} {schema}/> <TagRenderingInput path={path.concat(value)} {state} {schema} >
<button slot="upper-right" class="border-black border rounded-full p-1 w-fit h-fit"
on:click={() => {del(value)}}>
<TrashIcon class="w-4 h-4" />
</button>
</TagRenderingInput>
{:else} {:else}
{#each subparts as subpart} {#each subparts as subpart}
<SchemaBasedInput {state} path={fusePath(value, subpart.path)} schema={subpart} /> <SchemaBasedInput {state} path={fusePath(value, subpart.path)} schema={subpart} />
@ -105,5 +118,11 @@
</div> </div>
{/each} {/each}
{/if} {/if}
<button on:click={createItem}>Add {article} {singular}</button> <div class="flex">
<button on:click={() => createItem()}>Add {article} {singular}</button>
{#if path.length === 1 && path[0] === "tagRenderings"}
<button on:click={() => {createItem();}}>Add a builtin tagRendering</button>
{/if}
<slot name="extra-button" />
</div>
</div> </div>

View file

@ -10,6 +10,7 @@
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"; } from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
import EditLayerState from "./EditLayerState"; import EditLayerState from "./EditLayerState";
import { onDestroy } from "svelte"; import { onDestroy } from "svelte";
import type { JsonSchemaType } from "./jsonSchema";
export let state: EditLayerState export let state: EditLayerState
@ -21,6 +22,9 @@
if(type === "rendered"){ if(type === "rendered"){
type = "translation" type = "translation"
} }
if(type.endsWith("[]")){
type = type.substring(0, type.length - 2)
}
const isTranslation =schema.hints.typehint === "translation" || schema.hints.typehint === "rendered" const isTranslation =schema.hints.typehint === "translation" || schema.hints.typehint === "rendered"
const configJson: QuestionableTagRenderingConfigJson = { const configJson: QuestionableTagRenderingConfigJson = {
@ -47,7 +51,23 @@
}] }]
} }
if (schema.type === "boolean" || (Array.isArray(schema.type) && schema.type.some(t => t["type"] === "boolean"))) { function mightBeBoolean(type: undefined | JsonSchemaType): boolean {
if(type === undefined){
return false
}
if(type["type"]){
type = type["type"]
}
if(type === "boolean"){
return true
}
if(!Array.isArray(type)){
return false
}
return type.some(t => mightBeBoolean(t) )
}
if (mightBeBoolean(schema.type)) {
configJson.mappings = configJson.mappings ?? [] configJson.mappings = configJson.mappings ?? []
configJson.mappings.push( configJson.mappings.push(
{ {
@ -101,7 +121,7 @@
{#if err !== undefined} {#if err !== undefined}
<span class="alert">{err}</span> <span class="alert">{err}</span>
{:else} {:else}
<div class="w-full"> <div class="w-full flex flex-col">
<TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags}/> <TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags}/>
</div> </div>
{/if} {/if}

View file

@ -1,31 +1,25 @@
<script lang="ts"> <script lang="ts">
import type { ConfigMeta } from "./configMeta"; import type { ConfigMeta } from "./configMeta";
import SchemaBasedField from "./SchemaBasedField.svelte"; import SchemaBasedField from "./SchemaBasedField.svelte";
import EditLayerState from "./EditLayerState"; import EditLayerState from "./EditLayerState";
import SchemaBasedArray from "./SchemaBasedArray.svelte"; import SchemaBasedArray from "./SchemaBasedArray.svelte";
import SchemaBaseMultiType from "./SchemaBaseMultiType.svelte"; import SchemaBasedMultiType from "./SchemaBasedMultiType.svelte";
import RegisteredTagInput from "./RegisteredTagInput.svelte"; import SchemaBasedTranslationInput from "./SchemaBasedTranslationInput.svelte";
import SchemaBasedTranslationInput from "./SchemaBasedTranslationInput.svelte";
export let schema: ConfigMeta export let schema: ConfigMeta;
export let state: EditLayerState export let state: EditLayerState;
export let path: (string | number)[] = [] export let path: (string | number)[] = [];
console.log("Constructing", path,"with schema", schema)
</script> </script>
{#if schema.hints.typehint === "tagrendering[]"} {#if schema.hints.typehint === "tagrendering[]"}
<!-- We cheat a bit here by matching this 'magical' type... --> <!-- We cheat a bit here by matching this 'magical' type... -->
<SchemaBasedArray {path} {state} {schema}/> <SchemaBasedArray {path} {state} {schema} />
{:else if schema.type === "array"} {:else if schema.type === "array"}
<SchemaBasedArray {path} {state} {schema}/> <SchemaBasedArray {path} {state} {schema} />
{:else if schema.hints.typehint === "tag"}
<RegisteredTagInput {state} {path} {schema}/>
{:else if schema.type === "translation"} {:else if schema.type === "translation"}
<SchemaBasedTranslationInput {path} {state} {schema}/> <SchemaBasedTranslationInput {path} {state} {schema} />
{:else if schema.hints.types} {:else if schema.hints.types}
<SchemaBaseMultiType {path} {state} {schema}/> <SchemaBasedMultiType {path} {state} {schema} />
{:else} {:else}
<SchemaBasedField {path} {state} {schema}/> <SchemaBasedField {path} {state} {schema} />
{/if} {/if}

View file

@ -26,7 +26,6 @@
const hasBooleanOption = (<JsonSchemaType[]>schema.type)?.findIndex(t => t["type"] === "boolean"); const hasBooleanOption = (<JsonSchemaType[]>schema.type)?.findIndex(t => t["type"] === "boolean");
const types = schema.hints.types.split(";"); const types = schema.hints.types.split(";");
if (hasBooleanOption >= 0) { if (hasBooleanOption >= 0) {
console.log(path.join("."), ": types are", types, ", boolean index is", hasBooleanOption);
types.splice(hasBooleanOption); types.splice(hasBooleanOption);
} }

View file

@ -2,118 +2,121 @@
* Allows to create `and` and `or` expressions graphically * Allows to create `and` and `or` expressions graphically
*/ */
import {UIEventSource} from "../../Logic/UIEventSource"; import { UIEventSource } from "../../Logic/UIEventSource";
import type {TagConfigJson} from "../../Models/ThemeConfig/Json/TagConfigJson"; import type { TagConfigJson } from "../../Models/ThemeConfig/Json/TagConfigJson";
import BasicTagInput from "./TagInput/BasicTagInput.svelte"; import BasicTagInput from "./TagInput/BasicTagInput.svelte";
import TagInput from "./TagInput/TagInput.svelte"; import FullTagInput from "./TagInput/FullTagInput.svelte";
import {TrashIcon} from "@babeard/svelte-heroicons/mini"; import { TrashIcon } from "@babeard/svelte-heroicons/mini";
export let tag: UIEventSource<TagConfigJson> export let tag: UIEventSource<TagConfigJson>;
let mode: "and" | "or" = "and" let mode: "and" | "or" = "and";
let basicTags: UIEventSource<UIEventSource<string>[]> = new UIEventSource([]) let basicTags: UIEventSource<UIEventSource<string>[]> = new UIEventSource([]);
/** /**
* Sub-expressions * Sub-expressions
*/ */
let expressions: UIEventSource<UIEventSource<TagConfigJson>[]> = new UIEventSource([]) let expressions: UIEventSource<UIEventSource<TagConfigJson>[]> = new UIEventSource([]);
export let uploadableOnly: boolean
export let overpassSupportNeeded: boolean export let uploadableOnly: boolean;
export let overpassSupportNeeded: boolean;
export let silent: boolean;
function update(_) { function update(_) {
let config: TagConfigJson = <any>{} let config: TagConfigJson = <any>{};
if (!mode) { if (!mode) {
return return;
} }
const tags = [] const tags = [];
const subpartSources = (<UIEventSource<string | TagConfigJson>[]>basicTags.data).concat(expressions.data) const subpartSources = (<UIEventSource<string | TagConfigJson>[]>basicTags.data).concat(expressions.data);
for (const src of subpartSources) { for (const src of subpartSources) {
const t = src.data const t = src.data;
if (!t) { if (!t) {
// We indicate upstream that this value is invalid // We indicate upstream that this value is invalid
tag.setData(undefined) tag.setData(undefined);
return return;
} }
tags.push(t) tags.push(t);
} }
if (tags.length === 1) { if (tags.length === 1) {
tag.setData(tags[0]) tag.setData(tags[0]);
} else { } else {
config[mode] = tags config[mode] = tags;
tag.setData(config) tag.setData(config);
} }
} }
function addBasicTag(value?: string) { function addBasicTag(value?: string) {
const src = new UIEventSource(value) const src = new UIEventSource(value);
basicTags.data.push(src); basicTags.data.push(src);
basicTags.ping() basicTags.ping();
src.addCallbackAndRunD(_ => update(_)) src.addCallbackAndRunD(_ => update(_));
} }
function removeTag(basicTag: UIEventSource<any>) { function removeTag(basicTag: UIEventSource<any>) {
const index = basicTags.data.indexOf(basicTag) const index = basicTags.data.indexOf(basicTag);
console.log("Removing", index, basicTag) console.log("Removing", index, basicTag);
if (index >= 0) { if (index >= 0) {
basicTag.setData(undefined) basicTag.setData(undefined);
basicTags.data.splice(index, 1) basicTags.data.splice(index, 1);
basicTags.ping() basicTags.ping();
} }
} }
function removeExpression(expr: UIEventSource<any>) { function removeExpression(expr: UIEventSource<any>) {
const index = expressions.data.indexOf(expr) const index = expressions.data.indexOf(expr);
if (index >= 0) { if (index >= 0) {
expr.setData(undefined) expr.setData(undefined);
expressions.data.splice(index, 1) expressions.data.splice(index, 1);
expressions.ping() expressions.ping();
} }
} }
function addExpression(expr?: TagConfigJson) { function addExpression(expr?: TagConfigJson) {
const src = new UIEventSource(expr) const src = new UIEventSource(expr);
expressions.data.push(src); expressions.data.push(src);
expressions.ping() expressions.ping();
src.addCallbackAndRunD(_ => update(_)) src.addCallbackAndRunD(_ => update(_));
} }
$: update(mode) $: update(mode);
expressions.addCallback(_ => update(_)) expressions.addCallback(_ => update(_));
basicTags.addCallback(_ => update(_)) basicTags.addCallback(_ => update(_));
let initialTag: TagConfigJson = tag.data let initialTag: TagConfigJson = tag.data;
function initWith(initialTag: TagConfigJson) { function initWith(initialTag: TagConfigJson) {
if (typeof initialTag === "string") { if (typeof initialTag === "string") {
addBasicTag(initialTag) addBasicTag(initialTag);
return return;
} }
mode = <"or" | "and">Object.keys(initialTag)[0] mode = <"or" | "and">Object.keys(initialTag)[0];
const subExprs = (<TagConfigJson[]>initialTag[mode]) const subExprs = (<TagConfigJson[]>initialTag[mode]);
if (subExprs.length == 0) { if (!subExprs || subExprs.length == 0) {
return return;
} }
if (subExprs.length == 1) { if (subExprs.length == 1) {
initWith(subExprs[0]) initWith(subExprs[0]);
return; return;
} }
for (const subExpr of subExprs) { for (const subExpr of subExprs) {
if (typeof subExpr === "string") { if (typeof subExpr === "string") {
addBasicTag(subExpr) addBasicTag(subExpr);
} else { } else {
addExpression(subExpr) addExpression(subExpr);
} }
} }
} }
if (!initialTag) { if (!initialTag) {
addBasicTag() addBasicTag();
} else { } else {
initWith(initialTag) initWith(initialTag);
} }
@ -122,37 +125,44 @@ if (!initialTag) {
<div class="flex items-center"> <div class="flex items-center">
<select bind:value={mode}> {#if !uploadableOnly}
<option value="and">and</option> <select bind:value={mode}>
{#if !uploadableOnly} <option value="and">and</option>
<option value="or">or</option> <option value="or">or</option>
{/if} </select>
</select> {/if}
<div class="border-l-4 border-black flex flex-col ml-1 pl-1"> <div class="border-l-4 border-black flex flex-col ml-1 pl-1">
{#each $basicTags as basicTag (basicTag)} {#each $basicTags as basicTag (basicTag)}
<div class="flex"> <div class="flex">
<BasicTagInput {overpassSupportNeeded} {uploadableOnly} tag={basicTag}/> <BasicTagInput {silent} {overpassSupportNeeded} {uploadableOnly} tag={basicTag} />
<button class="border border-black rounded-full w-fit h-fit p-0" on:click={() => removeTag(basicTag)}> {#if $basicTags.length + $expressions.length > 1}
<TrashIcon class="w-4 h-4 p-1"/> <button class="border border-black rounded-full w-fit h-fit p-0"
</button> on:click={() => removeTag(basicTag)}>
<TrashIcon class="w-4 h-4 p-1" />
</button>
{/if}
</div> </div>
{/each} {/each}
{#each $expressions as expression} {#each $expressions as expression}
<TagInput {overpassSupportNeeded} {uploadableOnly} tag={expression}> <FullTagInput {silent} {overpassSupportNeeded} {uploadableOnly} tag={expression}>
<button slot="delete" on:click={() => removeExpression(expression)}> <button class="small" slot="delete" on:click={() => removeExpression(expression)}>
<TrashIcon class="w-4 h-4 p-1"/> <TrashIcon class="w-3 h-3 p-0" />
Delete subexpression Delete subexpression
</button> </button>
</TagInput> </FullTagInput>
{/each} {/each}
<div class="flex"> <div class="flex">
<button class="w-fit" on:click={() => addBasicTag()}> <button class="w-fit small" on:click={() => addBasicTag()}>
Add a tag Add a tag
</button> </button>
<button class="w-fit" on:click={() => addExpression()}> {#if !uploadableOnly}
Add an expression <!-- Do not allow to add an expression, as everything is 'and' anyway -->
</button> <button class="w-fit small" on:click={() => addExpression()}>
<slot name="delete"/> Add an expression
</button>
{/if}
<slot name="delete" />
</div> </div>
</div> </div>

View file

@ -2,58 +2,61 @@
* A small component showing statistics from tagInfo. * A small component showing statistics from tagInfo.
* Will show this in an 'alert' if very little (<250) tags are known * Will show this in an 'alert' if very little (<250) tags are known
*/ */
import {TagUtils} from "../../Logic/Tags/TagUtils"; import { TagUtils } from "../../Logic/Tags/TagUtils";
import {Store, UIEventSource} from "../../Logic/UIEventSource"; import { Store, UIEventSource } from "../../Logic/UIEventSource";
import type {TagInfoStats} from "../../Logic/Web/TagInfo"; import type { TagInfoStats } from "../../Logic/Web/TagInfo";
import TagInfo from "../../Logic/Web/TagInfo"; import TagInfo from "../../Logic/Web/TagInfo";
import {twMerge} from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import Loading from "../Base/Loading.svelte"; import Loading from "../Base/Loading.svelte";
export let tag: UIEventSource<string> export let silent = false;
const tagStabilized = tag.stabilized(500) export let tag: UIEventSource<string>;
const tagStabilized = tag.stabilized(500);
const tagInfoStats: Store<TagInfoStats> = tagStabilized.bind(tag => { const tagInfoStats: Store<TagInfoStats> = tagStabilized.bind(tag => {
if (!tag) { if (!tag) {
return undefined return undefined;
} }
try { try {
const t = TagUtils.Tag(tag) const t = TagUtils.Tag(tag);
const k = t["key"] const k = t["key"];
let v = t["value"] let v = t["value"];
if (typeof v !== "string") { if (typeof v !== "string") {
v = undefined v = undefined;
} }
if (!k) { if (!k) {
return undefined return undefined;
} }
return UIEventSource.FromPromise(TagInfo.global.getStats(k, v)) return UIEventSource.FromPromise(TagInfo.global.getStats(k, v));
} catch (e) { } catch (e) {
return undefined return undefined;
} }
}) });
const tagInfoUrl: Store<string> = tagStabilized.mapD(tag => { const tagInfoUrl: Store<string> = tagStabilized.mapD(tag => {
try { try {
const t = TagUtils.Tag(tag) const t = TagUtils.Tag(tag);
const k = t["key"] const k = t["key"];
let v = t["value"] let v = t["value"];
if (typeof v !== "string") { if (typeof v !== "string") {
v = undefined v = undefined;
} }
if (!k) { if (!k) {
return undefined return undefined;
} }
return TagInfo.global.webUrl(k, v) return TagInfo.global.webUrl(k, v);
} catch (e) { } catch (e) {
return undefined return undefined;
} }
}) });
const total = tagInfoStats.mapD(data => data.data.find(i => i.type === "all").count) const total = tagInfoStats.mapD(data => data.data.find(i => i.type === "all").count);
</script> </script>
{#if $tagStabilized !== $tag} {#if $tagStabilized !== $tag}
<Loading/> {#if !silent}
{:else if $tagInfoStats } <Loading />
{/if}
{:else if $tagInfoStats && (!silent || $total < 250) }
<a href={$tagInfoUrl} target="_blank" class={twMerge(($total < 250) ? "alert" : "thanks", "w-fit link-underline")}> <a href={$tagInfoUrl} target="_blank" class={twMerge(($total < 250) ? "alert" : "thanks", "w-fit link-underline")}>
{$total} features on OSM have this tag {$total} features on OSM have this tag
</a> </a>

View file

@ -6,11 +6,14 @@
import Tr from "../../Base/Tr.svelte"; import Tr from "../../Base/Tr.svelte";
import {TagUtils} from "../../../Logic/Tags/TagUtils"; import {TagUtils} from "../../../Logic/Tags/TagUtils";
import TagInfoStats from "../TagInfoStats.svelte"; import TagInfoStats from "../TagInfoStats.svelte";
import { Translation } from "../../i18n/Translation";
export let tag: UIEventSource<string> = new UIEventSource<string>(undefined) export let tag: UIEventSource<string> = new UIEventSource<string>(undefined)
export let uploadableOnly: boolean export let uploadableOnly: boolean
export let overpassSupportNeeded: boolean export let overpassSupportNeeded: boolean
export let silent : boolean = false
let feedbackGlobal = tag.map(tag => { let feedbackGlobal = tag.map(tag => {
if (!tag) { if (!tag) {
return undefined return undefined
@ -24,11 +27,11 @@
}) })
let feedbackKey = new UIEventSource<string>(undefined) let feedbackKey = new UIEventSource<Translation>(undefined)
let keyValue = new UIEventSource<string>(undefined) let keyValue = new UIEventSource<string>(undefined)
let feedbackValue = new UIEventSource<string>(undefined) let feedbackValue = new UIEventSource<Translation>(undefined)
/** /**
* The value of the tag. The name is a bit confusing * The value of the tag. The name is a bit confusing
*/ */
@ -79,7 +82,11 @@
function setTag(_) { function setTag(_) {
const k = keyValue.data const k = keyValue.data
const v = valueValue.data const v = valueValue.data ?? ""
if(k === undefined || k === ""){
tag.setData(undefined)
return
}
const t = k + mode + v const t = k + mode + v
try { try {
TagUtils.Tag(t) TagUtils.Tag(t)
@ -116,5 +123,5 @@
{:else if $feedbackGlobal} {:else if $feedbackGlobal}
<Tr cls="alert" t={$feedbackGlobal}/> <Tr cls="alert" t={$feedbackGlobal}/>
{/if} {/if}
<TagInfoStats {tag}/> <TagInfoStats {silent} {tag}/>
</div> </div>

View file

@ -0,0 +1,19 @@
<script lang="ts">/**
* An element input a tag; has `and`, `or`, `regex`, ...
*/
import type { TagConfigJson } from "../../../Models/ThemeConfig/Json/TagConfigJson";
import { UIEventSource } from "../../../Logic/UIEventSource";
import TagExpression from "../TagExpression.svelte";
export let tag: UIEventSource<string | TagConfigJson>
export let uploadableOnly: boolean
export let overpassSupportNeeded: boolean
export let silent: boolean
</script>
<div class="m-2">
<TagExpression {silent} {overpassSupportNeeded} {tag} {uploadableOnly}>
<slot name="delete" slot="delete"/>
</TagExpression>
</div>

View file

@ -1,18 +0,0 @@
<script lang="ts">/**
* An element input a tag; has `and`, `or`, `regex`, ...
*/
import type {TagConfigJson} from "../../../Models/ThemeConfig/Json/TagConfigJson";
import {UIEventSource} from "../../../Logic/UIEventSource";
import TagExpression from "../TagExpression.svelte";
export let tag: UIEventSource<TagConfigJson>
export let uploadableOnly: boolean
export let overpassSupportNeeded: boolean
</script>
<div class="m-4">
<TagExpression {overpassSupportNeeded} {tag} {uploadableOnly}>
<slot name="delete" slot="delete"/>
</TagExpression>
</div>

View file

@ -0,0 +1,14 @@
<script lang="ts">
import SchemaBasedInput from "./SchemaBasedInput.svelte";
import EditLayerState from "./EditLayerState";
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
export let state: EditLayerState
export let path : (number | string)[]
let schema : TagRenderingConfig
</script>
XYZ

View file

@ -12,6 +12,11 @@ import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig";
import TagRenderingEditable from "../Popup/TagRendering/TagRenderingEditable.svelte"; import TagRenderingEditable from "../Popup/TagRendering/TagRenderingEditable.svelte";
import { UIEventSource } from "../../Logic/UIEventSource"; import { UIEventSource } from "../../Logic/UIEventSource";
import * as questions from "../../assets/generated/layers/questions.json"; import * as questions from "../../assets/generated/layers/questions.json";
import MappingInput from "./MappingInput.svelte";
import { TrashIcon } from "@rgossiaux/svelte-heroicons/outline";
import questionableTagRenderingSchemaRaw from "../../assets/schemas/questionabletagrenderingconfigmeta.json";
import SchemaBasedField from "./SchemaBasedField.svelte";
import Region from "./Region.svelte";
export let state: EditLayerState; export let state: EditLayerState;
export let schema: ConfigMeta; export let schema: ConfigMeta;
@ -19,11 +24,11 @@ export let path: (string | number)[];
let value = state.getCurrentValueFor(path); let value = state.getCurrentValueFor(path);
let mappings: MappingConfigJson[] = []; let mappingsBuiltin: MappingConfigJson[] = [];
for (const tr of questions.tagRenderings) { for (const tr of questions.tagRenderings) {
let description = tr["description"] ?? tr["question"] ?? "No description available"; let description = tr["description"] ?? tr["question"] ?? "No description available";
description = description["en"] ?? description; description = description["en"] ?? description;
mappings.push({ mappingsBuiltin.push({
if: "value=" + tr["id"], if: "value=" + tr["id"],
then: { then: {
"en": "Builtin <b>" + tr["id"] + "</b> <div class='subtle'>" + description + "</div>" "en": "Builtin <b>" + tr["id"] + "</b> <div class='subtle'>" + description + "</div>"
@ -34,28 +39,77 @@ for (const tr of questions.tagRenderings) {
const configBuiltin = new TagRenderingConfig(<QuestionableTagRenderingConfigJson>{ const configBuiltin = new TagRenderingConfig(<QuestionableTagRenderingConfigJson>{
question: "Which builtin element should be shown?", question: "Which builtin element should be shown?",
mappings mappings: mappingsBuiltin
}); });
const configOverride = <QuestionableTagRenderingConfigJson>{
render: "This is a builtin question which changes some properties. Editing those is not possible within MapComplete Studio"
};
const tags = new UIEventSource({ value }); const tags = new UIEventSource({ value });
tags.addCallbackAndRunD(tgs => { tags.addCallbackAndRunD(tgs => {
state.setValueAt(path, tgs["value"]); state.setValueAt(path, tgs["value"]);
}); });
let mappings: UIEventSource<MappingConfigJson[]> = state.getStoreFor([...path, "mappings"]);
const topLevelItems: Record<string, ConfigMeta> = {};
for (const item of questionableTagRenderingSchemaRaw) {
if (item.path.length === 1) {
topLevelItems[item.path[0]] = <ConfigMeta>item;
}
}
function initMappings() {
if (mappings.data === undefined) {
mappings.setData([]);
}
}
const freeformSchema = <ConfigMeta[]> questionableTagRenderingSchemaRaw.filter(schema => schema.path.length >= 1 && schema.path[0] === "freeform");
console.log("FreeformSchema:", freeformSchema)
</script> </script>
{#if typeof value === "string"} {#if typeof value === "string"}
<TagRenderingEditable config={configBuiltin} selectedElement={undefined} showQuestionIfUnknown={true} {state}
{tags} />
{:else} <div class="flex low-interaction">
<div> <TagRenderingEditable config={configBuiltin} selectedElement={undefined} showQuestionIfUnknown={true} {state}
TR{JSON.stringify(state.getCurrentValueFor(path))} {tags} />
<slot name="upper-right" />
</div> </div>
{:else}
<div class="flex flex-col w-full p-1 gap-y-1">
<div class="flex justify-end">
<slot name="upper-right" />
</div>
<SchemaBasedField {state} path={[...path,"question"]} schema={topLevelItems["question"]}></SchemaBasedField>
<SchemaBasedField {state} path={[...path,"questionHint"]} schema={topLevelItems["questionHint"]}></SchemaBasedField>
{#each ($mappings ?? []) as mapping, i (mapping)}
<div class="flex interactive w-full">
<MappingInput {mapping} {state} path={path.concat(["mappings", i])}>
<button slot="delete" class="rounded-full no-image-background" on:click={() => {
initMappings();
mappings.data.splice(i, 1)
mappings.ping()
}}>
<TrashIcon class="w-4 h-4" />
</button>
</MappingInput>
</div>
{/each}
<button class="small primary"
on:click={() =>{ initMappings(); mappings.data.push({if: undefined, then: {}}); mappings.ping()} }>
Add a mapping
</button>
<Region {state} {path} configs={freeformSchema}/>
<!-- {JSON.stringify(state.getCurrentValueFor(path))} <!-->
</div>
<!--
<Region configs={freeformSchema} {state} path={[...path, "freeform"]} /> -->
{/if} {/if}

View file

@ -38,6 +38,11 @@
<ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} /> <ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} />
Main action (disabled) Main action (disabled)
</button> </button>
<button class="small">
<ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} />
Small button
</button>
</div> </div>
<div class="flex"> <div class="flex">
<button> <button>
@ -91,6 +96,10 @@
<ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} /> <ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} />
Main action (disabled) Main action (disabled)
</button> </button>
<button class="small">
<ToSvelte construct={Svg.community_svg().SetClass("w-6 h-6")} />
Small button
</button>
</div> </div>
<div class="flex"> <div class="flex">
<button> <button>

View file

@ -57,7 +57,7 @@ export class Translation extends BaseUIElement {
if (count === 0) { if (count === 0) {
console.error( console.error(
"Constructing a translation, but the object containing translations is empty " + "Constructing a translation, but the object containing translations is empty " +
context (context ?? "No context given")
) )
throw `Constructing a translation, but the object containing translations is empty (${context})` throw `Constructing a translation, but the object containing translations is empty (${context})`
} }

File diff suppressed because it is too large Load diff

View file

@ -1,797 +0,0 @@
[
{
"path": [],
"required": false,
"hints": {},
"type": "object",
"description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead."
},
{
"path": [
"id"
],
"required": true,
"hints": {
"question": "What is the id of this tagRendering?"
},
"type": "string",
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n"
},
{
"path": [
"mappings"
],
"required": false,
"hints": {
"question": "What are common options?"
},
"type": "array",
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes\n"
},
{
"path": [
"mappings",
"if"
],
"required": true,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"then"
],
"required": true,
"hints": {
"typehint": "rendered"
},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "Shown if the 'if is fulfilled"
},
{
"path": [
"mappings",
"icon"
],
"required": false,
"hints": {
"typehint": "icon"
},
"type": [
{
"type": "object",
"properties": {
"path": {
"description": "The path to the icon\nType: icon",
"type": "string"
},
"class": {
"description": "Size of the image",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
],
"description": "An extra icon supporting the choice"
},
{
"path": [
"mappings",
"icon",
"path"
],
"required": true,
"hints": {
"typehint": "icon"
},
"type": "string",
"description": "The path to the icon"
},
{
"path": [
"mappings",
"icon",
"class"
],
"required": false,
"hints": {},
"type": "string",
"description": "Size of the image"
},
{
"path": [
"mappings",
"hideInAnswer"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": [
"string",
"boolean"
]
}
],
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}"
},
{
"path": [
"mappings",
"hideInAnswer",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"hideInAnswer",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"ifnot"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`"
},
{
"path": [
"mappings",
"ifnot",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"ifnot",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"addExtraTags"
],
"required": false,
"hints": {},
"type": "array",
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```"
},
{
"path": [
"mappings",
"priorityIf"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "If the searchable selector is picked, mappings with this item will have priority and show up even if the others are hidden\nUse this sparingly"
},
{
"path": [
"mappings",
"priorityIf",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"priorityIf",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"#"
],
"required": false,
"hints": {},
"type": "string",
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed"
},
{
"path": [
"multiAnswer"
],
"required": false,
"hints": {
"question": "Should a contributor be allowed to select multiple mappings?",
"iftrue": "allow to select multiple mappigns",
"iffalse": "only allow to select a single mapping",
"ifunset": "only allow to select a single mapping"
},
"type": "boolean",
"description": "If true, use checkboxes instead of radio buttons when asking the question\n\n"
},
{
"path": [
"freeform"
],
"required": false,
"hints": {},
"type": "object",
"description": "Allow freeform text input from the user"
},
{
"path": [
"freeform",
"type"
],
"required": false,
"hints": {
"question": "What is the input type?"
},
"type": "string",
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values"
},
{
"path": [
"freeform",
"placeholder"
],
"required": false,
"hints": {},
"description": "A (translated) text that is shown (as gray text) within the textfield"
},
{
"path": [
"freeform",
"helperArgs"
],
"required": false,
"hints": {},
"type": "array",
"description": "Extra parameters to initialize the input helper arguments.\nFor semantics, see the 'SpecialInputElements.md'"
},
{
"path": [
"freeform",
"addExtraTags"
],
"required": false,
"hints": {},
"type": "array",
"description": "If a value is added with the textfield, these extra tag is addded.\nUseful to add a 'fixme=freeform textfield used - to be checked'"
},
{
"path": [
"freeform",
"inline"
],
"required": false,
"hints": {},
"type": "boolean",
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present."
},
{
"path": [
"freeform",
"default"
],
"required": false,
"hints": {},
"type": "string",
"description": "default value to enter if no previous tagging is present.\nNormally undefined (aka do not enter anything)"
},
{
"path": [
"question"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only"
},
{
"path": [
"questionHint"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like"
},
{
"path": [
"labels"
],
"required": false,
"hints": {},
"type": "array",
"description": "A list of labels. These are strings that are used for various purposes, e.g. to filter them away"
},
{
"path": [
"render"
],
"required": false,
"hints": {
"typehint": "rendered",
"question": "What text should be rendered?"
},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "object",
"properties": {
"special": {
"allOf": [
{
"$ref": "#/definitions/Record<string,string|Record<string,string>>"
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
]
}
]
}
},
"required": [
"special"
]
},
{
"type": "string"
}
],
"description": "\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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`"
},
{
"path": [
"condition"
],
"required": false,
"hints": {
"question": "When should this item be shown?"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "\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```"
},
{
"path": [
"condition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"condition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"metacondition"
],
"required": false,
"hints": {
"question": "When should this item be shown (including special conditions)?"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "\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_"
},
{
"path": [
"metacondition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"metacondition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"description"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings"
},
{
"path": [
"classes"
],
"required": false,
"hints": {
"question": "What css-classes should be applied to showing this attribute?"
},
"type": "string",
"description": "\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)"
}
]

File diff suppressed because it is too large Load diff

View file

@ -6,17 +6,6 @@
"type": "object", "type": "object",
"description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead." "description": "A QuestionableTagRenderingConfigJson is a single piece of code which converts one ore more tags into a HTML-snippet.\nIf the desired tags are missing and a question is defined, a question will be shown instead."
}, },
{
"path": [
"id"
],
"required": true,
"hints": {
"question": "What is the id of this tagRendering?"
},
"type": "string",
"description": "The id of the tagrendering, should be an unique string.\nUsed to keep the translations in sync. Only used in the tagRenderings-array of a layerConfig, not requered otherwise.\n"
},
{ {
"path": [ "path": [
"mappings" "mappings"
@ -35,7 +24,8 @@
], ],
"required": true, "required": true,
"hints": { "hints": {
"typehint": "tag" "typehint": "tag",
"question": "What tags should be matched to show this option?"
}, },
"type": [ "type": [
{ {
@ -59,7 +49,7 @@
"type": "string" "type": "string"
} }
], ],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n" "description": "\nIf in 'question'-mode and the contributor selects this option, these tags will be applied to the object"
}, },
{ {
"path": [ "path": [
@ -68,7 +58,8 @@
], ],
"required": true, "required": true,
"hints": { "hints": {
"typehint": "rendered" "typehint": "rendered",
"question": "What corresponding text should be shown?"
}, },
"type": [ "type": [
{ {
@ -78,7 +69,7 @@
"type": "string" "type": "string"
} }
], ],
"description": "Shown if the 'if is fulfilled" "description": "Shown if the `if` is fulfilled"
}, },
{ {
"path": [ "path": [
@ -87,7 +78,9 @@
], ],
"required": false, "required": false,
"hints": { "hints": {
"typehint": "icon" "typehint": "icon",
"question": "What icon should be shown next to this mapping?",
"ifunset": "Show no icon"
}, },
"type": [ "type": [
{ {
@ -110,7 +103,7 @@
"type": "string" "type": "string"
} }
], ],
"description": "An extra icon supporting the choice" "description": "\nThis icon will only be shown if the value is known, it is not displayed in the options (but might be in the future)\n"
}, },
{ {
"path": [ "path": [
@ -142,7 +135,12 @@
"hideInAnswer" "hideInAnswer"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"typehint": "tag",
"question": "Under what circumstances should this mapping be <b>hidden</b> from the possibilities a contributor can pick?",
"iftrue": "Never show this mapping as option to pick",
"ifunset": "Always show this mapping as option to pick"
},
"type": [ "type": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -157,7 +155,7 @@
] ]
} }
], ],
"description": "In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}" "description": "\nIn some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation).\n\nIn the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user.\nIn this case, one of the mappings can be hiden by setting this flag.\n\nTo demonstrate an example making a default assumption:\n\nmappings: [\n {\n if: \"access=\", -- no access tag present, we assume accessible\n then: \"Accessible to the general public\",\n hideInAnswer: true\n },\n {\n if: \"access=yes\",\n then: \"Accessible to the general public\", -- the user selected this, we add that to OSM\n },\n {\n if: \"access=no\",\n then: \"Not accessible to the public\"\n }\n]\n\n\nFor example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`.\nThen, we would add two mappings:\n{\n if: \"operator=Agentschap Natuur en Bos\" -- the non-abbreviated version which should be uploaded\n then: \"Maintained by Agentschap Natuur en Bos\"\n},\n{\n if: \"operator=ANB\", -- we don't want to upload abbreviations\n then: \"Maintained by Agentschap Natuur en Bos\"\n hideInAnswer: true\n}\n\nHide in answer can also be a tagsfilter, e.g. to make sure an option is only shown when appropriate.\nKeep in mind that this is reverse logic: it will be hidden in the answer if the condition is true, it will thus only show in the case of a mismatch\n\ne.g., for toilets: if \"wheelchair=no\", we know there is no wheelchair dedicated room.\nFor the location of the changing table, the option \"in the wheelchair accessible toilet is weird\", so we write:\n\n{\n \"question\": \"Where is the changing table located?\"\n \"mappings\": [\n {\"if\":\"changing_table:location=female\",\"then\":\"In the female restroom\"},\n {\"if\":\"changing_table:location=male\",\"then\":\"In the male restroom\"},\n {\"if\":\"changing_table:location=wheelchair\",\"then\":\"In the wheelchair accessible restroom\", \"hideInAnswer\": \"wheelchair=no\"},\n\n ]\n}\n\nAlso have a look for the meta-tags\n{\n if: \"operator=Agentschap Natuur en Bos\",\n then: \"Maintained by Agentschap Natuur en Bos\",\n hideInAnswer: \"_country!=be\"\n}"
}, },
{ {
"path": [ "path": [
@ -233,7 +231,9 @@
"ifnot" "ifnot"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"question": "What tags should be applied if this mapping is _not_ chosen?"
},
"type": [ "type": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -245,7 +245,7 @@
"type": "string" "type": "string"
} }
], ],
"description": "Only applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`" "description": "\nOnly applicable if 'multiAnswer' is set.\nThis is for situations such as:\n`accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected.\nThis can be done with `ifnot`\nNote that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`.\nIf this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer`"
}, },
{ {
"path": [ "path": [
@ -321,9 +321,25 @@
"addExtraTags" "addExtraTags"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"typehint": "simple_tag[]",
"question": "What extra tags should be added to the object if this object is chosen?"
},
"type": "array", "type": "array",
"description": "If chosen as answer, these tags will be applied as well onto the object.\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```" "description": "\nIf chosen as answer, these tags will be applied onto the object, together with the tags from the `if`\nNot compatible with multiAnswer.\n\nThis can be used e.g. to erase other keys which indicate the 'not' value:\n```json\n{\n \"if\": \"crossing:marking=rainbow\",\n \"then\": \"This is a rainbow crossing\",\n \"addExtraTags\": [\"not:crossing:marking=\"]\n}\n```"
},
{
"path": [
"mappings",
"searchTerms"
],
"required": false,
"hints": {
"group": "hidden",
"question": "If there are many options, what search terms match too?"
},
"type": "object",
"description": "If there are many options, the mappings-radiobuttons will be replaced by an element with a searchfunction\n\nSearchterms (per language) allow to easily find an option if there are many options"
}, },
{ {
"path": [ "path": [
@ -331,7 +347,9 @@
"priorityIf" "priorityIf"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"group": "hidden"
},
"type": [ "type": [
{ {
"$ref": "#/definitions/{and:TagConfigJson[];}" "$ref": "#/definitions/{and:TagConfigJson[];}"
@ -419,7 +437,9 @@
"#" "#"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"group": "hidden"
},
"type": "string", "type": "string",
"description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed" "description": "Used for comments or to disable a validation\n\nignore-image-in-then: normally, a `then`-clause is not allowed to have an `img`-html-element as icons are preferred. In some cases (most notably title-icons), this is allowed"
}, },
@ -446,13 +466,101 @@
"type": "object", "type": "object",
"description": "Allow freeform text input from the user" "description": "Allow freeform text input from the user"
}, },
{
"path": [
"freeform",
"key"
],
"required": true,
"hints": {
"ifunset": "do not offer a freeform textfield as answer option"
},
"type": "string",
"description": "question What is the name of the attribute that should be written to?"
},
{ {
"path": [ "path": [
"freeform", "freeform",
"type" "type"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"question": "What is the input type?",
"suggestions": [
{
"if": "value=string",
"then": "<b>string</b> A simple piece of text"
},
{
"if": "value=text",
"then": "<b>text</b> A longer piece of text. Uses an textArea instead of a textField"
},
{
"if": "value=date",
"then": "<b>date</b> A date with date picker"
},
{
"if": "value=nat",
"then": "<b>nat</b> A whole, positive number or zero"
},
{
"if": "value=int",
"then": "<b>int</b> A whole number, either positive, negative or zero"
},
{
"if": "value=distance",
"then": "<b>distance</b> A geographical distance in meters (rounded at two points). Will give an extra minimap with a measurement tool. Arguments: [ zoomlevel, preferredBackgroundMapType (comma separated) ], e.g. `[\"21\", \"map,photo\"]"
},
{
"if": "value=direction",
"then": "<b>direction</b> A geographical direction, in degrees. 0° is north, 90° is east, ... Will return a value between 0 (incl) and 360 (excl)."
},
{
"if": "value=wikidata",
"then": "<b>wikidata</b> A wikidata identifier, e.g. Q42. "
},
{
"if": "value=pnat",
"then": "<b>pnat</b> A strict positive number"
},
{
"if": "value=float",
"then": "<b>float</b> A decimal number"
},
{
"if": "value=pfloat",
"then": "<b>pfloat</b> A positive decimal number or zero"
},
{
"if": "value=email",
"then": "<b>email</b> An email adress"
},
{
"if": "value=url",
"then": "<b>url</b> The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed"
},
{
"if": "value=phone",
"then": "<b>phone</b> A phone number"
},
{
"if": "value=opening_hours",
"then": "<b>opening_hours</b> Has extra elements to easily input when a POI is opened. "
},
{
"if": "value=color",
"then": "<b>color</b> Shows a color picker"
},
{
"if": "value=icon",
"then": "<b>icon</b> Makes sure that a valid .svg-path is added"
},
{
"if": "value=fediverse",
"then": "<b>fediverse</b> Validates fediverse addresses and normalizes them into `@username@server`-format"
}
]
},
"type": "string", "type": "string",
"description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values" "description": "The type of the text-field, e.g. 'string', 'nat', 'float', 'date',...\nSee Docs/SpecialInputElements.md and UI/Input/ValidatedTextField.ts for supported values"
}, },
@ -491,9 +599,12 @@
"inline" "inline"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"question": "Show the freeform as box within the question?",
"ifunset": "do not show the"
},
"type": "boolean", "type": "boolean",
"description": "When set, influences the way a question is asked.\nInstead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout.\nNote that this will be set automatically if no special elements are present." "description": "Instead of showing a full-width text field, the text field will be shown within the rendering of the question.\n\nThis combines badly with special input elements, as it'll distort the layout."
}, },
{ {
"path": [ "path": [
@ -510,7 +621,10 @@
"question" "question"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"question": "What question should be shown to the contributor?",
"ifunset": "This tagrendering will be shown if it is known, but cannot be edited by the contributor, effectively resutling in a read-only rendering"
},
"type": [ "type": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -519,14 +633,17 @@
"type": "string" "type": "string"
} }
], ],
"description": "If it turns out that this tagRendering doesn't match _any_ value, then we show this question.\nIf undefined, the question is never asked and this tagrendering is read-only" "description": "\nA question is presented ot the user if no mapping matches and the 'freeform' key is not set as well.\n"
}, },
{ {
"path": [ "path": [
"questionHint" "questionHint"
], ],
"required": false, "required": false,
"hints": {}, "hints": {
"question": "Should some extra information be shown to the contributor, alongside the question?",
"ifunset": "No extra hint is given"
},
"type": [ "type": [
{ {
"$ref": "#/definitions/Record<string,string>" "$ref": "#/definitions/Record<string,string>"
@ -535,7 +652,7 @@
"type": "string" "type": "string"
} }
], ],
"description": "A hint which is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like" "description": "This hint is shown in subtle text under the question.\nThis can give some extra information on what the answer should ook like"
}, },
{ {
"path": [ "path": [
@ -589,7 +706,61 @@
"type": "string" "type": "string"
} }
], ],
"description": "\nThis piece of text will be shown in the infobox.\nNote that \"{key}\"-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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`" "description": "\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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`"
},
{
"path": [
"icon"
],
"required": false,
"hints": {
"typehint": "icon",
"question": "what icon should be shown next to the 'render' value?"
},
"type": [
{
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
],
"description": "An icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value"
},
{
"path": [
"icon",
"path"
],
"required": true,
"hints": {
"typehint": "icon"
},
"type": "string",
"description": "The path to the icon"
},
{
"path": [
"icon",
"class"
],
"required": false,
"hints": {},
"type": "string",
"description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)"
}, },
{ {
"path": [ "path": [

View file

@ -49,7 +49,61 @@
"type": "string" "type": "string"
} }
], ],
"description": "\nThis piece of text will be shown in the infobox.\nNote that \"{key}\"-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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`" "description": "\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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`"
},
{
"path": [
"icon"
],
"required": false,
"hints": {
"typehint": "icon",
"question": "what icon should be shown next to the 'render' value?"
},
"type": [
{
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
],
"description": "An icon shown next to the rendering; typically shown pretty small\nThis is only shown next to the \"render\" value"
},
{
"path": [
"icon",
"path"
],
"required": true,
"hints": {
"typehint": "icon"
},
"type": "string",
"description": "The path to the icon"
},
{
"path": [
"icon",
"class"
],
"required": false,
"hints": {},
"type": "string",
"description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)"
}, },
{ {
"path": [ "path": [
@ -72,72 +126,6 @@
], ],
"description": "\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```" "description": "\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```"
}, },
{
"path": [
"condition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"condition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{ {
"path": [ "path": [
"metacondition" "metacondition"
@ -159,72 +147,6 @@
], ],
"description": "\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_" "description": "\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_"
}, },
{
"path": [
"metacondition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"metacondition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{ {
"path": [ "path": [
"freeform" "freeform"
@ -256,39 +178,6 @@
"type": "array", "type": "array",
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes" "description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes"
}, },
{
"path": [
"mappings",
"if"
],
"required": true,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{ {
"path": [ "path": [
"mappings", "mappings",
@ -317,7 +206,8 @@
"required": false, "required": false,
"hints": { "hints": {
"typehint": "icon", "typehint": "icon",
"question": "What icon should be added to this mapping?" "question": "What icon should be added to this mapping?",
"inline": "<img src='{icon}' class=\"w-8 h-8\" /> {icon}"
}, },
"type": [ "type": [
{ {

View file

@ -1,396 +0,0 @@
[
{
"path": [],
"required": false,
"hints": {},
"type": "object",
"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"
},
{
"path": [
"render"
],
"required": false,
"hints": {
"typehint": "rendered",
"question": "What text should be rendered?"
},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "object",
"properties": {
"special": {
"allOf": [
{
"$ref": "#/definitions/Record<string,string|Record<string,string>>"
},
{
"type": "object",
"properties": {
"type": {
"type": "string"
}
},
"required": [
"type"
]
}
]
}
},
"required": [
"special"
]
},
{
"type": "string"
}
],
"description": "\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. '&lt;a href='{website}'>{website}&lt;/a>' or include images such as `This is of type A &lt;br>&lt;img src='typeA-icon.svg' />`"
},
{
"path": [
"condition"
],
"required": false,
"hints": {
"question": "When should this item be shown?"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "\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```"
},
{
"path": [
"condition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"condition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"metacondition"
],
"required": false,
"hints": {
"question": "When should this item be shown (including special conditions)?"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"$ref": "#/definitions/{or:TagConfigJson[];}"
},
{
"type": "string"
}
],
"description": "\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_"
},
{
"path": [
"metacondition",
"and"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"metacondition",
"or"
],
"required": false,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"freeform"
],
"required": false,
"hints": {
"question": "Should a freeform text field be shown?",
"ifunset": "Do not add a freeform text field"
},
"type": "object",
"description": "Allow freeform text input from the user"
},
{
"path": [
"freeform",
"key"
],
"required": true,
"hints": {},
"type": "string",
"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"
},
{
"path": [
"mappings"
],
"required": false,
"hints": {},
"type": "array",
"description": "Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes"
},
{
"path": [
"mappings",
"if"
],
"required": true,
"hints": {
"typehint": "tag"
},
"type": [
{
"$ref": "#/definitions/{and:TagConfigJson[];}"
},
{
"type": "object",
"properties": {
"or": {
"type": "array",
"items": {
"$ref": "#/definitions/TagConfigJson"
}
}
},
"required": [
"or"
]
},
{
"type": "string"
}
],
"description": "The main representation of Tags.\nSee https://github.com/pietervdvn/MapComplete/blob/develop/Docs/Tags_format.md for more documentation\n"
},
{
"path": [
"mappings",
"then"
],
"required": true,
"hints": {
"typehint": "rendered",
"question": "What text should be shown?"
},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "\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"
},
{
"path": [
"mappings",
"icon"
],
"required": false,
"hints": {
"typehint": "icon",
"question": "What icon should be added to this mapping?"
},
"type": [
{
"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-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)",
"type": "string"
}
},
"required": [
"path"
]
},
{
"type": "string"
}
],
"description": "An icon supporting this mapping; typically shown pretty small"
},
{
"path": [
"mappings",
"icon",
"path"
],
"required": true,
"hints": {
"typehint": "icon"
},
"type": "string",
"description": "The path to the icon"
},
{
"path": [
"mappings",
"icon",
"class"
],
"required": false,
"hints": {},
"type": "string",
"description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-<classtype>', so defining your own in combination with a custom CSS is possible (but discouraged)"
},
{
"path": [
"description"
],
"required": false,
"hints": {},
"type": [
{
"$ref": "#/definitions/Record<string,string>"
},
{
"type": "string"
}
],
"description": "A human-readable text explaining what this tagRendering does.\nMostly used for the shared tagrenderings"
},
{
"path": [
"classes"
],
"required": false,
"hints": {
"question": "What css-classes should be applied to showing this attribute?"
},
"type": "string",
"description": "\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)"
}
]

View file

@ -161,8 +161,27 @@ input[type=text] {
* This very important section defines what the various input elements look like within the 'low-interaction' and 'interactive'-blocks * This very important section defines what the various input elements look like within the 'low-interaction' and 'interactive'-blocks
*/ */
button.small, .button.small {
line-height: 1rem;
margin: 0;
margin-left: 0.5rem;
padding: 0.25rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
height: fit-content;
font-size: unset;
border: 2px solid var(--button-background);
border-radius: 0.5rem;
font-weight: normal;
transition: all 250ms;
--tw-text-opacity: 1;
--tw-bg-opacity: 1;
background: var(--low-interaction-background);
color: var(--low-interaction-foreground);
}
button, .button { button, .button {
align-items: center;
display: inline-flex; display: inline-flex;
line-height: 1.25rem; line-height: 1.25rem;
margin: 0.2rem; margin: 0.2rem;
@ -171,7 +190,6 @@ button, .button {
padding-right: 0.6rem; padding-right: 0.6rem;
font-size: large; font-size: large;
font-weight: bold; font-weight: bold;
/*-- invisible border: rendered on hover*/
border: 2px solid var(--button-background); border: 2px solid var(--button-background);
border-radius: 0.5rem; border-radius: 0.5rem;
transition: all 250ms; transition: all 250ms;
@ -185,20 +203,7 @@ button, .button {
box-shadow: 0 5px 10px #88888888; box-shadow: 0 5px 10px #88888888;
} }
button.small, .button.small {
line-height: 1rem;
margin: 0;
padding: 0.1rem;
font-size: unset;
/*-- invisible border: rendered on hover*/
border: 2px solid var(--low-interaction-background);
border-radius: 0.1rem;
transition: all 250ms;
--tw-text-opacity: 1;
--tw-bg-opacity: 1;
background: var(--low-interaction-background);
color: var(--low-interaction-foreground);
}
button.selected, .button.selected { button.selected, .button.selected {
background-color: var(--catch-detail-color); background-color: var(--catch-detail-color);

View file

@ -3,12 +3,6 @@ import * as theme from "./assets/generated/themes/bookcases.json"
import ThemeViewState from "./Models/ThemeViewState" import ThemeViewState from "./Models/ThemeViewState"
import Combine from "./UI/Base/Combine" import Combine from "./UI/Base/Combine"
import SpecialVisualizations from "./UI/SpecialVisualizations" import SpecialVisualizations from "./UI/SpecialVisualizations"
import SvelteUIElement from "./UI/Base/SvelteUIElement"
import TagInput from "./UI/Studio/TagInput/TagInput.svelte"
import { UIEventSource } from "./Logic/UIEventSource"
import { TagsFilter } from "./Logic/Tags/TagsFilter"
import { VariableUiElement } from "./UI/Base/VariableUIElement"
import { TagConfigJson } from "./Models/ThemeConfig/Json/TagConfigJson"
function testspecial() { function testspecial() {
const layout = new LayoutConfig(<any>theme, true) // qp.data === "" ? : new AllKnownLayoutsLazy().get(qp.data) const layout = new LayoutConfig(<any>theme, true) // qp.data === "" ? : new AllKnownLayoutsLazy().get(qp.data)
@ -20,9 +14,6 @@ function testspecial() {
new Combine(all).AttachTo("maindiv") new Combine(all).AttachTo("maindiv")
} }
const tag = new UIEventSource<TagConfigJson>(undefined)
new SvelteUIElement(TagInput, { tag }).AttachTo("maindiv")
new VariableUiElement(tag.map((t) => JSON.stringify(t))).AttachTo("extradiv")
/*/ /*/
testspecial() testspecial()
//*/ //*/

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Stylesheet testing grounds</title> <title>Stylesheet testing grounds</title>
<link href="./index.css" rel="stylesheet"/> <link href="./css/index-tailwind-output.css" rel="stylesheet"/>
</head> </head>
<body> <body>
<div id="main"></div> <div id="main"></div>