From 682b68a094c3d729472e86707f7412ca89939822 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 18 Feb 2022 23:10:27 +0100 Subject: [PATCH] Regenerate schemas, more fixes to images and licenses --- Docs/Schemas/LayerConfigJson.schema.json | 33 +- Docs/Schemas/LayerConfigJsonJSC.ts | 33 +- Docs/Schemas/LayoutConfigJson.schema.json | 33 +- Docs/Schemas/LayoutConfigJsonJSC.ts | 33 +- .../LineRenderingConfigJson.schema.json | 23 +- Docs/Schemas/LineRenderingConfigJsonJSC.ts | 23 +- .../PointRenderingConfigJson.schema.json | 23 +- Docs/Schemas/PointRenderingConfigJsonJSC.ts | 23 +- .../TagRenderingConfigJson.schema.json | 23 +- Docs/Schemas/TagRenderingConfigJsonJSC.ts | 23 +- Docs/Schemas/TilesourceConfigJson.schema.json | 23 +- Docs/Schemas/TilesourceConfigJsonJSC.ts | 23 +- Models/ThemeConfig/Conversion/FixImages.ts | 24 +- Models/ThemeConfig/Conversion/PrepareLayer.ts | 16 +- Models/ThemeConfig/Conversion/PrepareTheme.ts | 4 + Models/ThemeConfig/Conversion/Validation.ts | 24 +- Models/ThemeConfig/LayoutConfig.ts | 2 +- Utils.ts | 16 +- .../bike_repair_station/license_info.json | 14 + .../charging_station/charging_station.json | 34 +- .../charging_station.protojson | 2 +- assets/layers/charging_station/csvToJson.ts | 2 +- assets/layoutconfigmeta.json | 749 ++++++++++++++++++ assets/tagrenderingconfigmeta.json | 38 + assets/themes/buurtnatuur/buurtnatuur.json | 9 +- assets/themes/campersite/campersite.json | 2 +- assets/themes/campersite/license_info.json | 20 +- ...ohnmobilstellplatz.jpg => social_image.jpg} | Bin assets/themes/cyclofix/cyclofix.json | 2 +- assets/themes/grb_import/grb.json | 8 +- langs/themes/icon.json | 21 + langs/themes/nl.json | 6 +- scripts/generateLayerOverview.ts | 7 +- test/LegacyThemeLoader.spec.ts | 100 ++- 34 files changed, 1298 insertions(+), 118 deletions(-) rename assets/themes/campersite/{Barßel_Wohnmobilstellplatz.jpg => social_image.jpg} (100%) create mode 100644 langs/themes/icon.json diff --git a/Docs/Schemas/LayerConfigJson.schema.json b/Docs/Schemas/LayerConfigJson.schema.json index 52f9f1e69..9e72ff1a3 100644 --- a/Docs/Schemas/LayerConfigJson.schema.json +++ b/Docs/Schemas/LayerConfigJson.schema.json @@ -426,6 +426,16 @@ "items": { "$ref": "#/definitions/default_2" } + }, + "syncSelection": { + "description": "If set, synchronizes wether or not this layer is selected.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "enum": [ + "global", + "local", + "no", + "theme-only" + ], + "type": "string" } }, "required": [ @@ -606,7 +616,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/LayerConfigJsonJSC.ts b/Docs/Schemas/LayerConfigJsonJSC.ts index 35dc011ac..0348fcb91 100644 --- a/Docs/Schemas/LayerConfigJsonJSC.ts +++ b/Docs/Schemas/LayerConfigJsonJSC.ts @@ -426,6 +426,16 @@ export default { "items": { "$ref": "#/definitions/default_2" } + }, + "syncSelection": { + "description": "If set, synchronizes wether or not this layer is selected.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "enum": [ + "global", + "local", + "no", + "theme-only" + ], + "type": "string" } }, "required": [ @@ -604,7 +614,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/LayoutConfigJson.schema.json b/Docs/Schemas/LayoutConfigJson.schema.json index dcfda9918..3321c1eed 100644 --- a/Docs/Schemas/LayoutConfigJson.schema.json +++ b/Docs/Schemas/LayoutConfigJson.schema.json @@ -460,7 +460,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", @@ -1314,6 +1335,16 @@ "items": { "$ref": "#/definitions/default_2" } + }, + "syncSelection": { + "description": "If set, synchronizes wether or not this layer is selected.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "enum": [ + "global", + "local", + "no", + "theme-only" + ], + "type": "string" } }, "required": [ diff --git a/Docs/Schemas/LayoutConfigJsonJSC.ts b/Docs/Schemas/LayoutConfigJsonJSC.ts index 14f441f16..49ca6c05e 100644 --- a/Docs/Schemas/LayoutConfigJsonJSC.ts +++ b/Docs/Schemas/LayoutConfigJsonJSC.ts @@ -458,7 +458,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", @@ -1304,6 +1325,16 @@ export default { "items": { "$ref": "#/definitions/default_2" } + }, + "syncSelection": { + "description": "If set, synchronizes wether or not this layer is selected.\n\nno: Do not sync at all, always revert to default\nlocal: keep selection on local storage\ntheme-only: sync via OSM, but this layer will only be toggled in this theme\nglobal: all layers with this ID will be synced accross all themes", + "enum": [ + "global", + "local", + "no", + "theme-only" + ], + "type": "string" } }, "required": [ diff --git a/Docs/Schemas/LineRenderingConfigJson.schema.json b/Docs/Schemas/LineRenderingConfigJson.schema.json index a410d218d..278e857e4 100644 --- a/Docs/Schemas/LineRenderingConfigJson.schema.json +++ b/Docs/Schemas/LineRenderingConfigJson.schema.json @@ -260,7 +260,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/LineRenderingConfigJsonJSC.ts b/Docs/Schemas/LineRenderingConfigJsonJSC.ts index 918f1b4c8..f4a2e76d3 100644 --- a/Docs/Schemas/LineRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/LineRenderingConfigJsonJSC.ts @@ -258,7 +258,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/PointRenderingConfigJson.schema.json b/Docs/Schemas/PointRenderingConfigJson.schema.json index 5f14ee615..715988459 100644 --- a/Docs/Schemas/PointRenderingConfigJson.schema.json +++ b/Docs/Schemas/PointRenderingConfigJson.schema.json @@ -264,7 +264,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/PointRenderingConfigJsonJSC.ts b/Docs/Schemas/PointRenderingConfigJsonJSC.ts index 30827308f..1f37ef54a 100644 --- a/Docs/Schemas/PointRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/PointRenderingConfigJsonJSC.ts @@ -262,7 +262,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/TagRenderingConfigJson.schema.json b/Docs/Schemas/TagRenderingConfigJson.schema.json index 9b74df032..1c595208d 100644 --- a/Docs/Schemas/TagRenderingConfigJson.schema.json +++ b/Docs/Schemas/TagRenderingConfigJson.schema.json @@ -100,7 +100,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/TagRenderingConfigJsonJSC.ts b/Docs/Schemas/TagRenderingConfigJsonJSC.ts index 2bc849c6e..172740e9c 100644 --- a/Docs/Schemas/TagRenderingConfigJsonJSC.ts +++ b/Docs/Schemas/TagRenderingConfigJsonJSC.ts @@ -100,7 +100,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/TilesourceConfigJson.schema.json b/Docs/Schemas/TilesourceConfigJson.schema.json index cef3d5386..a7ae626b5 100644 --- a/Docs/Schemas/TilesourceConfigJson.schema.json +++ b/Docs/Schemas/TilesourceConfigJson.schema.json @@ -208,7 +208,28 @@ }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Docs/Schemas/TilesourceConfigJsonJSC.ts b/Docs/Schemas/TilesourceConfigJsonJSC.ts index 15178b758..21d48703c 100644 --- a/Docs/Schemas/TilesourceConfigJsonJSC.ts +++ b/Docs/Schemas/TilesourceConfigJsonJSC.ts @@ -206,7 +206,28 @@ export default { }, "icon": { "description": "An icon supporting this mapping; typically shown pretty small\nType: icon", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "path": { + "description": "The path to the icon\nType: icon", + "type": "string" + }, + "class": { + "description": "A hint to mapcomplete on how to render this icon within the mapping.\nThis is translated to 'mapping-icon-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] }, "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}", diff --git a/Models/ThemeConfig/Conversion/FixImages.ts b/Models/ThemeConfig/Conversion/FixImages.ts index ef315fd95..ebeb0223d 100644 --- a/Models/ThemeConfig/Conversion/FixImages.ts +++ b/Models/ThemeConfig/Conversion/FixImages.ts @@ -6,9 +6,11 @@ import * as tagrenderingmetapaths from "../../../assets/tagrenderingconfigmeta.j export class ExtractImages extends Conversion { private _isOfficial: boolean; - constructor(isOfficial: boolean) { + private _sharedTagRenderings: Map; + constructor(isOfficial: boolean, sharedTagRenderings: Map) { super("Extract all images from a layoutConfig using the meta paths",[],"ExctractImages"); this._isOfficial = isOfficial; + this._sharedTagRenderings = sharedTagRenderings; } convert(json: LayoutConfigJson, context: string): { result: string[], errors: string[], warnings: string[] } { @@ -29,8 +31,19 @@ export class ExtractImages extends Conversion { const found = Utils.CollectPath(metapath.path, json) if (mightBeTr) { // We might have tagRenderingConfigs containing icons here - for (const foundImage of found) { + for (const {path, leaf} of found) { + const foundImage = leaf; if (typeof foundImage === "string") { + + if(foundImage == ""){ + errors.push(context+"."+path.join(".")+" Found an empty image") + } + + if(this._sharedTagRenderings?.has(foundImage)){ + // This is not an image, but a shared tag rendering + continue + } + allFoundImages.push(foundImage) } else{ // This is a tagRendering where every rendered value might be an icon! @@ -45,6 +58,11 @@ export class ExtractImages extends Conversion { } } allFoundImages.push(...fromPath.filter(i => typeof i === "string")) + for (const pathAndImg of fromPath) { + if(pathAndImg.leaf === "" || pathAndImg.leaf["path"] == ""){ + errors.push(context+[...path,...pathAndImg.path].join(".")+": Found an empty image at ") + } + } } } @@ -108,7 +126,7 @@ export class FixImages extends DesugaringStep { continue } const mightBeTr = Array.isArray(metapath.type) && metapath.type.some(t => t["$ref"] == "#/definitions/TagRenderingConfigJson") - Utils.WalkPath(metapath.path, json, leaf => { + Utils.WalkPath(metapath.path, json, (leaf, path) => { if (typeof leaf === "string") { return replaceString(leaf) } diff --git a/Models/ThemeConfig/Conversion/PrepareLayer.ts b/Models/ThemeConfig/Conversion/PrepareLayer.ts index 70b9815d7..88fc0276e 100644 --- a/Models/ThemeConfig/Conversion/PrepareLayer.ts +++ b/Models/ThemeConfig/Conversion/PrepareLayer.ts @@ -75,14 +75,14 @@ class ExpandTagRendering extends Conversion { new PreparePersonalTheme(state), new OnEveryConcat("layers", new SubstituteLayer(state)), new SetDefault("socialImage", "assets/SocialImage.png", true), + // We expand all tagrenderings first... new OnEvery("layers", new PrepareLayer(state)), + // Then we apply the override all new ApplyOverrideAll(), + // And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings! + new OnEvery("layers", new PrepareLayer(state)), new AddDefaultLayers(state), new AddDependencyLayersToTheme(state), new AddImportLayers(), diff --git a/Models/ThemeConfig/Conversion/Validation.ts b/Models/ThemeConfig/Conversion/Validation.ts index 2e87d706c..571cc7d3a 100644 --- a/Models/ThemeConfig/Conversion/Validation.ts +++ b/Models/ThemeConfig/Conversion/Validation.ts @@ -12,6 +12,7 @@ import {ExtractImages} from "./FixImages"; import ScriptUtils from "../../../scripts/ScriptUtils"; import {And} from "../../../Logic/Tags/And"; import Translations from "../../../UI/i18n/Translations"; +import Svg from "../../../Svg"; class ValidateLanguageCompleteness extends DesugaringStep { @@ -50,12 +51,14 @@ class ValidateTheme extends DesugaringStep { private readonly _path?: string; private readonly knownImagePaths: Set; private readonly _isBuiltin: boolean; + private _sharedTagRenderings: Map; - constructor(knownImagePaths: Set, path: string, isBuiltin: boolean) { + constructor(knownImagePaths: Set, path: string, isBuiltin: boolean, sharedTagRenderings: Map) { super("Doesn't change anything, but emits warnings and errors", [], "ValidateTheme"); this.knownImagePaths = knownImagePaths; this._path = path; this._isBuiltin = isBuiltin; + this._sharedTagRenderings = sharedTagRenderings; } convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors: string[], warnings: string[], information: string[] } { @@ -78,7 +81,7 @@ class ValidateTheme extends DesugaringStep { } { // Check images: are they local, are the licenses there, is the theme icon square, ... - const images = new ExtractImages(this._isBuiltin).convertStrict(json, "validation") + const images = new ExtractImages(this._isBuiltin, this._sharedTagRenderings).convertStrict(json, "validation") const remoteImages = images.filter(img => img.indexOf("http") == 0) for (const remoteImage of remoteImages) { errors.push("Found a remote image: " + remoteImage + " in theme " + json.id + ", please download it.") @@ -93,8 +96,11 @@ class ValidateTheme extends DesugaringStep { continue } if (image.match(/[a-z]*/)) { - // This is a builtin img, e.g. 'checkmark' or 'crosshair' - continue; + + if(Svg.All[image + ".svg"] !== undefined){ + // This is a builtin img, e.g. 'checkmark' or 'crosshair' + continue; + } } if (this.knownImagePaths !== undefined && !this.knownImagePaths.has(image)) { @@ -163,10 +169,10 @@ class ValidateTheme extends DesugaringStep { } export class ValidateThemeAndLayers extends Fuse { - constructor(knownImagePaths: Set, path: string, isBuiltin: boolean) { + constructor(knownImagePaths: Set, path: string, isBuiltin: boolean, sharedTagRenderings: Map) { super("Validates a theme and the contained layers", - new ValidateTheme(knownImagePaths, path, isBuiltin), - new OnEvery("layers", new ValidateLayer(knownImagePaths, undefined, false)) + new ValidateTheme(knownImagePaths, path, isBuiltin, sharedTagRenderings), + new OnEvery("layers", new ValidateLayer(undefined, false)) ); } } @@ -302,12 +308,10 @@ export class ValidateLayer extends DesugaringStep { * @private */ private readonly _path?: string; - private readonly knownImagePaths?: Set; private readonly _isBuiltin: boolean; - constructor(knownImagePaths: Set, path: string, isBuiltin: boolean) { + constructor(path: string, isBuiltin: boolean) { super("Doesn't change anything, but emits warnings and errors", [], "ValidateLayer"); - this.knownImagePaths = knownImagePaths; this._path = path; this._isBuiltin = isBuiltin; } diff --git a/Models/ThemeConfig/LayoutConfig.ts b/Models/ThemeConfig/LayoutConfig.ts index 1875b8d99..eb22b8443 100644 --- a/Models/ThemeConfig/LayoutConfig.ts +++ b/Models/ThemeConfig/LayoutConfig.ts @@ -71,7 +71,7 @@ export default class LayoutConfig { this.credits = json.credits; this.version = json.version; this.language = json.mustHaveLanguage ?? Array.from(Object.keys(json.title)); - this.usedImages = Array.from(new ExtractImages(official).convertStrict(json, "while extracting the images of " + json.id + " " + context ?? "")).sort() + this.usedImages = Array.from(new ExtractImages(official, undefined).convertStrict(json, "while extracting the images of " + json.id + " " + context ?? "")).sort() { if (typeof json.title === "string") { throw `The title of a theme should always be a translation, as it sets the corresponding languages (${context}.title). The themenID is ${this.id}; the offending object is ${JSON.stringify(json.title)} which is a ${typeof json.title})` diff --git a/Utils.ts b/Utils.ts index cdf0cb26b..9132347f4 100644 --- a/Utils.ts +++ b/Utils.ts @@ -358,16 +358,16 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be * * The leaf objects are replaced by the function */ - public static WalkPath(path: string[], object: any, replaceLeaf: ((leaf: any) => any)) { + public static WalkPath(path: string[], object: any, replaceLeaf: ((leaf: any, travelledPath: string[]) => any), travelledPath: string[] = []) { const head = path[0] if (path.length === 1) { // We have reached the leaf const leaf = object[head]; if (leaf !== undefined) { if(Array.isArray(leaf)){ - object[head] = leaf.map(replaceLeaf) + object[head] = leaf.map(o => replaceLeaf(o, travelledPath)) }else{ - object[head] = replaceLeaf(leaf) + object[head] = replaceLeaf(leaf, travelledPath) } } return @@ -381,10 +381,10 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be return; } if (Array.isArray(sub)) { - sub.forEach(el => Utils.WalkPath(path.slice(1), el, replaceLeaf)) + sub.forEach((el, i) => Utils.WalkPath(path.slice(1), el, replaceLeaf, [...travelledPath, head, ""+i])) return; } - Utils.WalkPath(path.slice(1), sub, replaceLeaf) + Utils.WalkPath(path.slice(1), sub, replaceLeaf, [...travelledPath,head]) } /** @@ -393,7 +393,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be * * The leaf objects are collected in the list */ - public static CollectPath(path: string[], object: any, collectedList = []): any[] { + public static CollectPath(path: string[], object: any, collectedList: {leaf: any, path: string[]}[] = [], travelledPath: string[] = []): {leaf: any, path: string[]}[] { if (object === undefined || object === null) { return collectedList; } @@ -417,13 +417,13 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be } if (Array.isArray(sub)) { - sub.forEach(el => Utils.CollectPath(path.slice(1), el, collectedList)) + sub.forEach((el, i) => Utils.CollectPath(path.slice(1), el, collectedList, [...travelledPath,head,""+i])) return collectedList; } if (typeof sub !== "object") { return collectedList; } - return Utils.CollectPath(path.slice(1), sub, collectedList) + return Utils.CollectPath(path.slice(1), sub, collectedList,[...travelledPath, head]) } /** diff --git a/assets/layers/bike_repair_station/license_info.json b/assets/layers/bike_repair_station/license_info.json index 4ad68baaf..fb56c0978 100644 --- a/assets/layers/bike_repair_station/license_info.json +++ b/assets/layers/bike_repair_station/license_info.json @@ -84,6 +84,20 @@ "https://osoc.be/editions/2020/cyclofix" ] }, + { + "path": "repair_station_broken_pump.svg", + "license": "CC-BY-SA", + "authors": [ + "Pieter Fiers", + "Thibault Declercq", + "Pierre Barban", + "Joost Schouppe", + "Pieter Vander Vennet" + ], + "sources": [ + "https://osoc.be/editions/2020/cyclofix" + ] + }, { "path": "repair_station_example.jpg", "license": "CC-BY-SA 4.0", diff --git a/assets/layers/charging_station/charging_station.json b/assets/layers/charging_station/charging_station.json index 38926d2d9..e7c89c5d2 100644 --- a/assets/layers/charging_station/charging_station.json +++ b/assets/layers/charging_station/charging_station.json @@ -241,7 +241,7 @@ }, "hideInAnswer": true, "icon": { - "path": "CEE7_4F.svg", + "path": "./assets/layers/charging_station/CEE7_4F.svg", "class": "medium" } }, @@ -270,7 +270,7 @@ }, "hideInAnswer": true, "icon": { - "path": "TypeE.svg", + "path": "./assets/layers/charging_station/TypeE.svg", "class": "medium" } }, @@ -325,7 +325,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Chademo_type4.svg", + "path": "./assets/layers/charging_station/Chademo_type4.svg", "class": "medium" } }, @@ -380,7 +380,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type1_J1772.svg", + "path": "./assets/layers/charging_station/Type1_J1772.svg", "class": "medium" } }, @@ -435,7 +435,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type1_J1772.svg", + "path": "./assets/layers/charging_station/Type1_J1772.svg", "class": "medium" } }, @@ -490,7 +490,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type1-ccs.svg", + "path": "./assets/layers/charging_station/Type1-ccs.svg", "class": "medium" } }, @@ -545,7 +545,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Tesla-hpwc-model-s.svg", + "path": "./assets/layers/charging_station/Tesla-hpwc-model-s.svg", "class": "medium" } }, @@ -600,7 +600,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type2_socket.svg", + "path": "./assets/layers/charging_station/Type2_socket.svg", "class": "medium" } }, @@ -655,7 +655,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type2_CCS.svg", + "path": "./assets/layers/charging_station/Type2_CCS.svg", "class": "medium" } }, @@ -710,7 +710,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type2_tethered.svg", + "path": "./assets/layers/charging_station/Type2_tethered.svg", "class": "medium" } }, @@ -765,7 +765,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type2_CCS.svg", + "path": "./assets/layers/charging_station/Type2_CCS.svg", "class": "medium" } }, @@ -826,7 +826,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Tesla-hpwc-model-s.svg", + "path": "./assets/layers/charging_station/Tesla-hpwc-model-s.svg", "class": "medium" } }, @@ -887,7 +887,7 @@ }, "hideInAnswer": true, "icon": { - "path": "Type2_tethered.svg", + "path": "./assets/layers/charging_station/Type2_tethered.svg", "class": "medium" } }, @@ -916,7 +916,7 @@ }, "hideInAnswer": true, "icon": { - "path": "usb_port.svg", + "path": "./assets/layers/charging_station/usb_port.svg", "class": "medium" } }, @@ -967,7 +967,7 @@ }, "hideInAnswer": true, "icon": { - "path": "bosch-3pin.svg", + "path": "./assets/layers/charging_station/bosch-3pin.svg", "class": "medium" } }, @@ -1018,7 +1018,7 @@ }, "hideInAnswer": true, "icon": { - "path": "bosch-5pin.svg", + "path": "./assets/layers/charging_station/bosch-5pin.svg", "class": "medium" } } @@ -3953,7 +3953,7 @@ "operational_status=broken" ] }, - "then": "cross:#c22;" + "then": "close:#c22;" }, { "if": { diff --git a/assets/layers/charging_station/charging_station.protojson b/assets/layers/charging_station/charging_station.protojson index 72fb64d1d..35a2fc40a 100644 --- a/assets/layers/charging_station/charging_station.protojson +++ b/assets/layers/charging_station/charging_station.protojson @@ -764,7 +764,7 @@ "operational_status=broken" ] }, - "then": "cross:#c22;" + "then": "close:#c22;" }, { "if": { diff --git a/assets/layers/charging_station/csvToJson.ts b/assets/layers/charging_station/csvToJson.ts index e138243f7..ea1d55ac9 100644 --- a/assets/layers/charging_station/csvToJson.ts +++ b/assets/layers/charging_station/csvToJson.ts @@ -131,7 +131,7 @@ function run(file, protojson) { then: txt, hideInAnswer: true, icon:{ - path: e.image, + path: `./assets/layers/charging_station/${e.image}`, class:"medium" } } diff --git a/assets/layoutconfigmeta.json b/assets/layoutconfigmeta.json index 40abedbc8..c596f78b9 100644 --- a/assets/layoutconfigmeta.json +++ b/assets/layoutconfigmeta.json @@ -485,6 +485,48 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "isShown", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "isShown", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -753,6 +795,48 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "title", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "title", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -1014,6 +1098,48 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "titleIcons", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "titleIcons", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -1291,6 +1417,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "icon", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "icon", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -1585,6 +1755,52 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "iconBadges", + "then", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "iconBadges", + "then", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -1852,6 +2068,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "iconSize", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "iconSize", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -2116,6 +2376,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "rotation", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "rotation", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -2380,6 +2684,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "label", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "label", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -2651,6 +2999,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "color", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "color", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -2918,6 +3310,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "width", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "width", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -3182,6 +3618,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "dashArray", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "dashArray", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -3446,6 +3926,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "lineCap", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "lineCap", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -3714,6 +4238,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "fill", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "fill", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -3978,6 +4546,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "fillColor", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "fillColor", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -4242,6 +4854,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "mapRendering", + "offset", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "mapRendering", + "offset", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -4625,6 +5281,48 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "tagRenderings", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "tagRenderings", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -4871,6 +5569,50 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "layers", + "tagRenderings", + "renderings", + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "layers", + "tagRenderings", + "renderings", + "mappings", + "icon", + "class" + ], "type": "string" }, { @@ -5160,6 +5902,13 @@ ], "type": "boolean" }, + { + "path": [ + "layers", + "syncSelection" + ], + "type": "string" + }, { "path": [ "layers", diff --git a/assets/tagrenderingconfigmeta.json b/assets/tagrenderingconfigmeta.json index fd9483b82..6f7b349c1 100644 --- a/assets/tagrenderingconfigmeta.json +++ b/assets/tagrenderingconfigmeta.json @@ -138,6 +138,44 @@ "icon" ], "typeHint": "icon", + "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-', so defining your own in combination with a custom CSS is possible (but discouraged)", + "type": "string" + } + }, + "required": [ + "class", + "path" + ] + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "mappings", + "icon", + "path" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "mappings", + "icon", + "class" + ], "type": "string" }, { diff --git a/assets/themes/buurtnatuur/buurtnatuur.json b/assets/themes/buurtnatuur/buurtnatuur.json index 1ef2e4f1d..991654c46 100644 --- a/assets/themes/buurtnatuur/buurtnatuur.json +++ b/assets/themes/buurtnatuur/buurtnatuur.json @@ -504,7 +504,8 @@ ] }, "then": { - "nl": "Dit gebied wordt beheerd door Natuurpunt" + "nl": "Dit gebied wordt beheerd door Natuurpunt", + "icon": "./assets/themes/buurtnatuur/Natuurpunt.jpg" } }, { @@ -514,7 +515,8 @@ ] }, "then": { - "nl": "Dit gebied wordt beheerd door {operator}" + "nl": "Dit gebied wordt beheerd door {operator}", + "icon": "./assets/themes/buurtnatuur/Natuurpunt.jpg" }, "hideInAnswer": true }, @@ -525,7 +527,8 @@ ] }, "then": { - "nl": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos" + "nl": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos", + "icon": "./assets/themes/buurtnatuur/ANB.jpg" } }, { diff --git a/assets/themes/campersite/campersite.json b/assets/themes/campersite/campersite.json index 59acbe7c6..bc792011e 100644 --- a/assets/themes/campersite/campersite.json +++ b/assets/themes/campersite/campersite.json @@ -42,7 +42,7 @@ "startLon": 3.14, "startZoom": 14, "widenFactor": 1.5, - "socialImage": "./assets/themes/campersite/Bar%C3%9Fel_Wohnmobilstellplatz.jpg", + "socialImage": "./assets/themes/campersite/social_image.jpg", "layers": [ { "id": "caravansites", diff --git a/assets/themes/campersite/license_info.json b/assets/themes/campersite/license_info.json index 6e12c74c2..d1b076033 100644 --- a/assets/themes/campersite/license_info.json +++ b/assets/themes/campersite/license_info.json @@ -1,14 +1,4 @@ [ - { - "path": "Barßel_Wohnmobilstellplatz.jpg", - "license": "CC-BY-SA 3.0", - "authors": [ - "ES01" - ], - "sources": [ - "https://commons.wikimedia.org/wiki/File:Bar%C3%9Fel_Wohnmobilstellplatz.jpg" - ] - }, { "path": "caravan.svg", "license": "CC0", @@ -41,5 +31,15 @@ "https://github.com/osmandapp/Osmand/blob/master/LICENSE", "https://github.com/osmandapp/OsmAnd-resources/blob/16892d8b2fc00dd422abfb2fef967d5ccd05eeac/icons/svg/poi/sanitary_dump_station.svg" ] + }, + { + "path": "social_image.jpg", + "license": "CC-BY-SA 3.0", + "authors": [ + "ES01" + ], + "sources": [ + "https://commons.wikimedia.org/wiki/File:Bar%C3%9Fel_Wohnmobilstellplatz.jpg" + ] } ] \ No newline at end of file diff --git a/assets/themes/campersite/Barßel_Wohnmobilstellplatz.jpg b/assets/themes/campersite/social_image.jpg similarity index 100% rename from assets/themes/campersite/Barßel_Wohnmobilstellplatz.jpg rename to assets/themes/campersite/social_image.jpg diff --git a/assets/themes/cyclofix/cyclofix.json b/assets/themes/cyclofix/cyclofix.json index 99ec5635b..82a94047f 100644 --- a/assets/themes/cyclofix/cyclofix.json +++ b/assets/themes/cyclofix/cyclofix.json @@ -33,7 +33,7 @@ "startLon": 0, "startZoom": 1, "widenFactor": 2, - "socialImage": "assets/themes/cyclofix/logo.svg", + "socialImage": "./assets/themes/cyclofix/logo.svg", "layers": [ "bike_cafe", "bike_shop", diff --git a/assets/themes/grb_import/grb.json b/assets/themes/grb_import/grb.json index c184f8594..28b9c62a4 100644 --- a/assets/themes/grb_import/grb.json +++ b/assets/themes/grb_import/grb.json @@ -11,14 +11,13 @@ "en": "This theme is an attempt to help automating the GRB import.", "hu": "Ez a sablon a flandriai GRB épületimportálás automatizlását kívánja megkönnyíteni." }, - "maintainer": "", + "maintainer": "Pieter Vander Vennet", "icon": "./assets/themes/grb_import/logo.svg", "version": "0", "startLat": 51.0249, "startLon": 4.026489, "startZoom": 9, "widenFactor": 2, - "socialImage": "", "clustering": { "maxZoom": 15 }, @@ -605,15 +604,14 @@ }, "iconSize": "50,50,center", "icon": { - "render": "./assets/themes/grb_import/housenumber_blank.svg", "mappings": [ { "if": "_intersects_with_other_features~*", "then": "./assets/themes/grb_import/warning.svg" }, { - "if": "addr:housenumber=", - "then": "" + "if": "addr:housenumber~*", + "then": "./assets/themes/grb_import/housenumber_blank.svg" } ] }, diff --git a/langs/themes/icon.json b/langs/themes/icon.json new file mode 100644 index 000000000..9544aaac9 --- /dev/null +++ b/langs/themes/icon.json @@ -0,0 +1,21 @@ +{ + "buurtnatuur": { + "overrideAll": { + "tagRenderings+": { + "1": { + "mappings": { + "1": { + "then": "./assets/themes/buurtnatuur/Natuurpunt.jpg" + }, + "2": { + "then": "./assets/themes/buurtnatuur/Natuurpunt.jpg" + }, + "3": { + "then": "./assets/themes/buurtnatuur/ANB.jpg" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 4e77e8d09..660702e1a 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -134,13 +134,13 @@ "1": { "mappings": { "1": { - "then": "Dit gebied wordt beheerd door Natuurpunt" + "then": "Dit gebied wordt beheerd door Natuurpunt" }, "2": { - "then": "Dit gebied wordt beheerd door {operator}" + "then": "Dit gebied wordt beheerd door {operator}" }, "3": { - "then": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos" + "then": "Dit gebied wordt beheerd door het Agentschap Natuur en Bos" } }, "question": "Wie beheert dit gebied?", diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index 4ee9aa129..a14a88623 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -169,7 +169,7 @@ class LayerOverviewUtils { for (const sharedLayerJson of layerFiles) { const context = "While building builtin layer " + sharedLayerJson.path const fixed = prepLayer.convertStrict(sharedLayerJson.parsed, context) - const validator = new ValidateLayer(knownImagePaths, sharedLayerJson.path, true); + const validator = new ValidateLayer(sharedLayerJson.path, true); validator.convertStrict(fixed, context) if (sharedLayers.has(fixed.id)) { @@ -200,7 +200,10 @@ class LayerOverviewUtils { new PrevalidateTheme().convertStrict(themeFile, themePath) themeFile = new PrepareTheme(convertState).convertStrict(themeFile, themePath) - new ValidateThemeAndLayers(knownImagePaths, themePath, true) + if(knownImagePaths === undefined){ + throw "Could not load known images/licenses" + } + new ValidateThemeAndLayers(knownImagePaths, themePath, true, convertState.tagRenderings) .convertStrict(themeFile, themePath) this.writeTheme(themeFile) diff --git a/test/LegacyThemeLoader.spec.ts b/test/LegacyThemeLoader.spec.ts index 83284c5be..85a3d5b17 100644 --- a/test/LegacyThemeLoader.spec.ts +++ b/test/LegacyThemeLoader.spec.ts @@ -5,7 +5,7 @@ import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingCon import {AddMiniMap} from "../Models/ThemeConfig/Conversion/PrepareTheme"; import {DetectMappingsWithImages, DetectShadowedMappings} from "../Models/ThemeConfig/Conversion/Validation"; import * as Assert from "assert"; -import {FixImages} from "../Models/ThemeConfig/Conversion/FixImages"; +import {ExtractImages, FixImages} from "../Models/ThemeConfig/Conversion/FixImages"; export default class LegacyThemeLoaderSpec extends T { @@ -144,7 +144,7 @@ export default class LegacyThemeLoaderSpec extends T { ] } - private static readonly verkeerde_borden ={ + private static readonly verkeerde_borden = { "id": "https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/VerkeerdeBordenDatabank.json", "title": { "nl": "VerkeerdeBordenDatabank", @@ -242,7 +242,7 @@ export default class LegacyThemeLoaderSpec extends T { "icon": "./TS_bolt.svg", iconBadges: [{ if: "id=yes", - then:{ + then: { mappings: [ { if: "id=yes", @@ -351,7 +351,6 @@ export default class LegacyThemeLoaderSpec extends T { } - constructor() { super([ ["Walking_node_theme", () => { @@ -423,9 +422,9 @@ export default class LegacyThemeLoaderSpec extends T { } ] }, "test"); - T.isTrue(r.errors.length > 0, "Failing case 0 is not detected") + T.isTrue(r.errors.length > 0, "Failing case 0 is not detected") - const r0 = new DetectShadowedMappings().convert( { + const r0 = new DetectShadowedMappings().convert({ mappings: [ { if: {or: ["key=value", "x=y"]}, @@ -440,34 +439,71 @@ export default class LegacyThemeLoaderSpec extends T { T.isTrue(r0.errors.length > 0, "Failing case 1 is not detected") } ], - ["Images are rewritten", () => { - const fixed = new FixImages(new Set()).convertStrict(LegacyThemeLoaderSpec.verkeerde_borden, "test") - const fixedValue = fixed.layers[0]["mapRendering"][0].icon - Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg", - fixedValue) + ["Images are rewritten", () => { + const fixed = new FixImages(new Set()).convertStrict(LegacyThemeLoaderSpec.verkeerde_borden, "test") + const fixedValue = fixed.layers[0]["mapRendering"][0].icon + Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/TS_bolt.svg", + fixedValue) - const fixedMapping = fixed.layers[0]["mapRendering"][0].iconBadges[0].then.mappings[0].then - Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg", - fixedMapping) - } ], - ["Images in 'thens' are detected", () => { - const r = new DetectMappingsWithImages().convert({ + const fixedMapping = fixed.layers[0]["mapRendering"][0].iconBadges[0].then.mappings[0].then + Assert.equal("https://raw.githubusercontent.com/seppesantens/MapComplete-Themes/main/VerkeerdeBordenDatabank/Something.svg", + fixedMapping) + }], + ["Images in 'thens' are detected", () => { + const r = new DetectMappingsWithImages().convert({ "mappings": [ - { - "if": "bicycle_parking=stands", - "then": { - "en": "Staple racks ", - "nl": "Nietjes ", - "fr": "Arceaux ", - "gl": "De roda (Stands) ", - "de": "Fahrradbügel ", - "hu": "Korlát ", - "it": "Archetti ", - "zh_Hant": "單車架 " - } - }]}, "test"); - T.isTrue(r.warnings.length > 0, "No images found"); - }] + { + "if": "bicycle_parking=stands", + "then": { + "en": "Staple racks ", + "nl": "Nietjes ", + "fr": "Arceaux ", + "gl": "De roda (Stands) ", + "de": "Fahrradbügel ", + "hu": "Korlát ", + "it": "Archetti ", + "zh_Hant": "單車架 " + } + }] + }, "test"); + T.isTrue(r.warnings.length > 0, "No images found"); + T.isTrue(r.warnings.some(msg => msg.indexOf("./assets/layers/bike_parking/staple.svg") >= 0), "staple.svg not mentioned"); + }], + ["Images in 'thens' icons are detected", () => { + const r = new ExtractImages(true).convert({ + "layers": [ + { + tagRenderings: [ + { + "mappings": [ + { + "if": "bicycle_parking=stands", + "then": { + "en": "Staple racks", + }, + "icon": { + path: "./assets/layers/bike_parking/staple.svg", + class: "small" + } + }, + { + "if": "bicycle_parking=stands", + "then": { + "en": "Bollard", + }, + "icon": "./assets/layers/bike_parking/bollard.svg", + } + ] + } + ] + } + ] + }, "test"); + const images = r.result + T.isTrue(images.length > 0, "No images found"); + T.isTrue(images.findIndex(img => img =="./assets/layers/bike_parking/staple.svg") >= 0, "staple.svg not mentioned"); + T.isTrue(images.findIndex(img => img == "./assets/layers/bike_parking/bollard.svg") >= 0, "bollard.svg not mentioned"); + }] ] ); }