diff --git a/Docs/BuiltinIndex.md b/Docs/BuiltinIndex.md
index 75fc2a4109..680260c765 100644
--- a/Docs/BuiltinIndex.md
+++ b/Docs/BuiltinIndex.md
@@ -21,6 +21,7 @@
+ [bicycle_rental.*bicycle_rental](#bicycle_rental*bicycle_rental)
+ [bike_cleaning.bike_cleaning-service:bicycle:cleaning:charge](#bike_cleaningbike_cleaning-service:bicycle:cleaning:charge)
+ [wheelchair-access](#wheelchair-access)
+ + [smoking](#smoking)
+ [service:electricity](#serviceelectricity)
+ [dog-access](#dog-access)
+ [climbing.website](#climbingwebsite)
@@ -287,6 +288,17 @@
+### smoking
+
+
+
+
+
+ - cafe_pub
+
+
+
+
### service:electricity
diff --git a/Docs/BuiltinQuestions.md b/Docs/BuiltinQuestions.md
index b75eea8790..95ba3a4913 100644
--- a/Docs/BuiltinQuestions.md
+++ b/Docs/BuiltinQuestions.md
@@ -33,11 +33,13 @@ The following items can be easily reused in your layers
+ [last_edit](#last_edit)
+ [all_tags](#all_tags)
+ [level](#level)
+ + [smoking](#smoking)
+ [default](#default)
+ [defaults](#defaults)
+ [isOpen](#isopen)
+ [phonelink](#phonelink)
+ [emaillink](#emaillink)
+ + [smokingicon](#smokingicon)
+ [sharelink](#sharelink)
@@ -341,6 +343,21 @@ On what level is this feature located?
+### smoking
+
+
+
+Is smoking allowed at {title()}?
+
+
+
+ - Smoking is allowed
+ - Smoking is not allowed
+ - Smoking is allowed outside.
+
+
+
+
### default
@@ -377,7 +394,7 @@ Read-only tagrendering
-
+
Read-only tagrendering
@@ -387,12 +404,26 @@ Read-only tagrendering
-
+
Read-only tagrendering
+### smokingicon
+
+
+
+Read-only tagrendering
+
+
+
+ -
+ -
+
+
+
+
### sharelink
diff --git a/Docs/Layers/cafe_pub.md b/Docs/Layers/cafe_pub.md
index 00b04ef59a..52de985fdd 100644
--- a/Docs/Layers/cafe_pub.md
+++ b/Docs/Layers/cafe_pub.md
@@ -40,10 +40,10 @@ Elements must have the all of following tags to be shown on this layer:
- - amenity=bar|amenity=pub|amenity=cafe|amenity=biergarten
+ - amenity=bar|amenity=pub|amenity=cafe|amenity=biergarten|amenity=nightclub
-[Execute on overpass](http://overpass-turbo.eu/?Q=%5Bout%3Ajson%5D%5Btimeout%3A90%5D%3B(%20%20%20%20nwr%5B%22amenity%22%3D%22bar%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22pub%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22cafe%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22biergarten%22%5D(%7B%7Bbbox%7D%7D)%3B%0A)%3Bout%20body%3B%3E%3Bout%20skel%20qt%3B)
+[Execute on overpass](http://overpass-turbo.eu/?Q=%5Bout%3Ajson%5D%5Btimeout%3A90%5D%3B(%20%20%20%20nwr%5B%22amenity%22%3D%22bar%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22pub%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22cafe%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22biergarten%22%5D(%7B%7Bbbox%7D%7D)%3B%0A%20%20%20%20nwr%5B%22amenity%22%3D%22nightclub%22%5D(%7B%7Bbbox%7D%7D)%3B%0A)%3Bout%20body%3B%3E%3Bout%20skel%20qt%3B)
@@ -61,12 +61,13 @@ this quick overview is incomplete
attribute | type | values which are supported by this layer
----------- | ------ | ------------------------------------------
[
](https://taginfo.openstreetmap.org/keys/name#values) [name](https://wiki.openstreetmap.org/wiki/Key:name) | [string](../SpecialInputElements.md#string) |
-[
](https://taginfo.openstreetmap.org/keys/amenity#values) [amenity](https://wiki.openstreetmap.org/wiki/Key:amenity) | Multiple choice | [pub](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dpub) [bar](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dbar) [cafe](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dcafe) [restaurant](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Drestaurant) [biergarten](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dbiergarten)
+[
](https://taginfo.openstreetmap.org/keys/amenity#values) [amenity](https://wiki.openstreetmap.org/wiki/Key:amenity) | Multiple choice | [pub](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dpub) [bar](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dbar) [cafe](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dcafe) [restaurant](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Drestaurant) [biergarten](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dbiergarten) [nightclub](https://wiki.openstreetmap.org/wiki/Tag:amenity%3Dnightclub)
[
](https://taginfo.openstreetmap.org/keys/opening_hours#values) [opening_hours](https://wiki.openstreetmap.org/wiki/Key:opening_hours) | [opening_hours](../SpecialInputElements.md#opening_hours) |
[
](https://taginfo.openstreetmap.org/keys/website#values) [website](https://wiki.openstreetmap.org/wiki/Key:website) | [url](../SpecialInputElements.md#url) |
[
](https://taginfo.openstreetmap.org/keys/email#values) [email](https://wiki.openstreetmap.org/wiki/Key:email) | [email](../SpecialInputElements.md#email) |
[
](https://taginfo.openstreetmap.org/keys/phone#values) [phone](https://wiki.openstreetmap.org/wiki/Key:phone) | [phone](../SpecialInputElements.md#phone) |
[
](https://taginfo.openstreetmap.org/keys/wheelchair#values) [wheelchair](https://wiki.openstreetmap.org/wiki/Key:wheelchair) | Multiple choice | [designated](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Ddesignated) [yes](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dlimited) [no](https://wiki.openstreetmap.org/wiki/Tag:wheelchair%3Dno)
+[
](https://taginfo.openstreetmap.org/keys/smoking#values) [smoking](https://wiki.openstreetmap.org/wiki/Key:smoking) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:smoking%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:smoking%3Dno) [outside](https://wiki.openstreetmap.org/wiki/Tag:smoking%3Doutside)
[
](https://taginfo.openstreetmap.org/keys/service:electricity#values) [service:electricity](https://wiki.openstreetmap.org/wiki/Key:service:electricity) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:service:electricity%3Dyes) [limited](https://wiki.openstreetmap.org/wiki/Tag:service:electricity%3Dlimited) [ask](https://wiki.openstreetmap.org/wiki/Tag:service:electricity%3Dask) [no](https://wiki.openstreetmap.org/wiki/Tag:service:electricity%3Dno)
[
](https://taginfo.openstreetmap.org/keys/dog#values) [dog](https://wiki.openstreetmap.org/wiki/Key:dog) | Multiple choice | [yes](https://wiki.openstreetmap.org/wiki/Tag:dog%3Dyes) [no](https://wiki.openstreetmap.org/wiki/Tag:dog%3Dno) [leashed](https://wiki.openstreetmap.org/wiki/Tag:dog%3Dleashed) [unleashed](https://wiki.openstreetmap.org/wiki/Tag:dog%3Dunleashed)
@@ -112,6 +113,7 @@ The question is What kind of cafe is this?
- A cafe to drink tea, coffee or an alcoholical bevarage in a quiet environment corresponds with amenity=cafe
- A restuarant where one can get a proper meal corresponds with amenity=restaurant
- An open space where beer is served, typically seen in Germany corresponds with amenity=biergarten
+ - This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks corresponds with amenity=nightclub
@@ -226,6 +228,23 @@ The question is Is this place accessible with a wheelchair?
+### smoking
+
+
+
+The question is Is smoking allowed at {title()}?
+
+
+
+
+
+ - Smoking is allowed corresponds with smoking=yes
+ - Smoking is not allowed corresponds with smoking=no
+ - Smoking is allowed outside. corresponds with smoking=outside
+
+
+
+
### service:electricity
diff --git a/Docs/TagInfo/mapcomplete_cafes_and_pubs.json b/Docs/TagInfo/mapcomplete_cafes_and_pubs.json
index 26d78bf69e..7f889ce4d1 100644
--- a/Docs/TagInfo/mapcomplete_cafes_and_pubs.json
+++ b/Docs/TagInfo/mapcomplete_cafes_and_pubs.json
@@ -30,6 +30,11 @@
"description": "The MapComplete theme Cafés and pubs has a layer Cafés and pubs showing features with this tag",
"value": "biergarten"
},
+ {
+ "key": "amenity",
+ "description": "The MapComplete theme Cafés and pubs has a layer Cafés and pubs showing features with this tag",
+ "value": "nightclub"
+ },
{
"key": "image",
"description": "The layer 'Cafés and pubs allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
@@ -75,6 +80,11 @@
"description": "Layer 'Cafés and pubs' shows amenity=biergarten with a fixed text, namely 'An open space where beer is served, typically seen in Germany' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "biergarten"
},
+ {
+ "key": "amenity",
+ "description": "Layer 'Cafés and pubs' shows amenity=nightclub with a fixed text, namely 'This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
+ "value": "nightclub"
+ },
{
"key": "opening_hours",
"description": "Layer 'Cafés and pubs' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Cafés and pubs')"
@@ -133,6 +143,21 @@
"description": "Layer 'Cafés and pubs' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
"value": "no"
},
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=yes with a fixed text, namely 'Smoking is allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
+ "value": "yes"
+ },
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=no with a fixed text, namely 'Smoking is not allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
+ "value": "no"
+ },
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=outside with a fixed text, namely 'Smoking is allowed outside.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
+ "value": "outside"
+ },
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Cafés and pubs')",
diff --git a/Docs/TagInfo/mapcomplete_personal.json b/Docs/TagInfo/mapcomplete_personal.json
index a5216ce228..146b216850 100644
--- a/Docs/TagInfo/mapcomplete_personal.json
+++ b/Docs/TagInfo/mapcomplete_personal.json
@@ -1920,6 +1920,11 @@
"description": "The MapComplete theme Personal theme has a layer Cafés and pubs showing features with this tag",
"value": "biergarten"
},
+ {
+ "key": "amenity",
+ "description": "The MapComplete theme Personal theme has a layer Cafés and pubs showing features with this tag",
+ "value": "nightclub"
+ },
{
"key": "image",
"description": "The layer 'Cafés and pubs allows to upload images and adds them under the 'image'-tag (and image:0, image:1, ... for multiple images). Furhtermore, this layer shows images based on the keys image, wikidata, wikipedia, wikimedia_commons and mapillary"
@@ -1965,6 +1970,11 @@
"description": "Layer 'Cafés and pubs' shows amenity=biergarten with a fixed text, namely 'An open space where beer is served, typically seen in Germany' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
"value": "biergarten"
},
+ {
+ "key": "amenity",
+ "description": "Layer 'Cafés and pubs' shows amenity=nightclub with a fixed text, namely 'This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
+ "value": "nightclub"
+ },
{
"key": "opening_hours",
"description": "Layer 'Cafés and pubs' shows and asks freeform values for key 'opening_hours' (in the MapComplete.osm.be theme 'Personal theme')"
@@ -2023,6 +2033,21 @@
"description": "Layer 'Cafés and pubs' shows wheelchair=no with a fixed text, namely 'This place is not reachable with a wheelchair' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
"value": "no"
},
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=yes with a fixed text, namely 'Smoking is allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
+ "value": "yes"
+ },
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=no with a fixed text, namely 'Smoking is not allowed' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
+ "value": "no"
+ },
+ {
+ "key": "smoking",
+ "description": "Layer 'Cafés and pubs' shows smoking=outside with a fixed text, namely 'Smoking is allowed outside.' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
+ "value": "outside"
+ },
{
"key": "service:electricity",
"description": "Layer 'Cafés and pubs' shows service:electricity=yes with a fixed text, namely 'There are plenty of domestic sockets available to customers seated indoors, where they can charge their electronics' and allows to pick this as a default answer (in the MapComplete.osm.be theme 'Personal theme')",
diff --git a/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts b/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
index 547f8c57b4..5d9ae5862d 100644
--- a/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
+++ b/Models/ThemeConfig/Conversion/LegacyJsonConvert.ts
@@ -18,10 +18,12 @@ export class UpdateLegacyLayer extends DesugaringStep {
-
+
private readonly _languages: string[];
constructor(...languages: string[]) {
@@ -98,8 +98,8 @@ class ValidateTheme extends DesugaringStep {
continue
}
if (image.match(/[a-z]*/)) {
-
- if(Svg.All[image + ".svg"] !== undefined){
+
+ if (Svg.All[image + ".svg"] !== undefined) {
// This is a builtin img, e.g. 'checkmark' or 'crosshair'
continue;// =>
}
@@ -121,18 +121,18 @@ class ValidateTheme extends DesugaringStep {
` Width = ${width} height = ${height}`;
(json.hideFromOverview ? warnings : errors).push(e)
}
-
+
const w = parseInt(width);
const h = parseInt(height)
- if(w < 370 || h < 370){
- const e : string = [
+ if (w < 370 || h < 370) {
+ const e: string = [
`the icon for theme ${json.id} is too small. Please rescale the icon at ${json.icon}`,
`Even though an SVG is 'infinitely scaleable', the icon should be dimensioned bigger. One of the build steps of the theme does convert the image to a PNG (to serve as PWA-icon) and having a small dimension will cause blurry images.`,
` Width = ${width} height = ${height}; we recommend a size of at least 500px * 500px and to use a square aspect ratio.`,
- ].join("\n");
+ ].join("\n");
(json.hideFromOverview ? warnings : errors).push(e)
}
-
+
})
} catch (e) {
console.error("Could not read " + json.icon + " due to " + e)
@@ -186,7 +186,7 @@ export class ValidateThemeAndLayers extends Fuse {
constructor(knownImagePaths: Set, path: string, isBuiltin: boolean, sharedTagRenderings: Map) {
super("Validates a theme and the contained layers",
new ValidateTheme(knownImagePaths, path, isBuiltin, sharedTagRenderings),
- new On("layers", new Each(new ValidateLayer(undefined, false)))
+ new On("layers", new Each(new ValidateLayer(undefined, false, knownImagePaths)))
);
}
}
@@ -222,22 +222,22 @@ class OverrideShadowingCheck extends DesugaringStep {
}
-class MiscThemeChecks extends DesugaringStep{
+class MiscThemeChecks extends DesugaringStep {
constructor() {
- super("Miscelleanous checks on the theme", [],"MiscThemesChecks");
+ super("Miscelleanous checks on the theme", [], "MiscThemesChecks");
}
-
+
convert(json: LayoutConfigJson, context: string): { result: LayoutConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
const warnings = []
const errors = []
- if(json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)){
- errors.push("The theme "+json.id+" has no 'layers' defined ("+context+")")
+ if (json.id !== "personal" && (json.layers === undefined || json.layers.length === 0)) {
+ errors.push("The theme " + json.id + " has no 'layers' defined (" + context + ")")
}
- if(json.socialImage === ""){
- warnings.push("Social image for theme "+json.id+" is the emtpy string")
+ if (json.socialImage === "") {
+ warnings.push("Social image for theme " + json.id + " is the emtpy string")
}
return {
- result :json,
+ result: json,
warnings,
errors
};
@@ -258,28 +258,29 @@ export class PrevalidateTheme extends Fuse {
export class DetectShadowedMappings extends DesugaringStep {
private readonly _calculatedTagNames: string[];
+
constructor(layerConfig?: LayerConfigJson) {
super("Checks that the mappings don't shadow each other", [], "DetectShadowedMappings");
this._calculatedTagNames = DetectShadowedMappings.extractCalculatedTagNames(layerConfig);
}
/**
- *
+ *
* DetectShadowedMappings.extractCalculatedTagNames({calculatedTags: ["_abc:=js()"]}) // => ["_abc"]
* DetectShadowedMappings.extractCalculatedTagNames({calculatedTags: ["_abc=js()"]}) // => ["_abc"]
*/
- private static extractCalculatedTagNames(layerConfig?: LayerConfigJson | {calculatedTags : string []}){
+ private static extractCalculatedTagNames(layerConfig?: LayerConfigJson | { calculatedTags: string [] }) {
return layerConfig?.calculatedTags?.map(ct => {
- if(ct.indexOf(':=') >= 0){
+ if (ct.indexOf(':=') >= 0) {
return ct.split(':=')[0]
}
return ct.split("=")[0]
}) ?? []
-
+
}
/**
- *
+ *
* // should detect a simple shadowed mapping
* const tr = {mappings: [
* {
@@ -319,20 +320,20 @@ export class DetectShadowedMappings extends DesugaringStep {
+ const parsedConditions = json.mappings.map((m, i) => {
const ctx = `${context}.mappings[${i}]`
const ifTags = TagUtils.Tag(m.if, ctx);
- if(m.hideInAnswer !== undefined && m.hideInAnswer !== false && m.hideInAnswer !== true){
- let conditionTags = TagUtils.Tag( m.hideInAnswer)
+ if (m.hideInAnswer !== undefined && m.hideInAnswer !== false && m.hideInAnswer !== true) {
+ let conditionTags = TagUtils.Tag(m.hideInAnswer)
// Merge the condition too!
return new And([conditionTags, ifTags])
}
return ifTags
})
for (let i = 0; i < json.mappings.length; i++) {
- if(!parsedConditions[i].isUsableAsAnswer()){
+ if (!parsedConditions[i].isUsableAsAnswer()) {
// There is no straightforward way to convert this mapping.if into a properties-object, so we simply skip this one
// Yes, it might be shadowed, but running this check is to difficult right now
continue
@@ -372,12 +373,14 @@ export class DetectShadowedMappings extends DesugaringStep {
- constructor() {
+ private knownImagePaths: Set;
+ constructor(knownImagePaths: Set) {
super("Checks that 'then'clauses in mappings don't have images, but use 'icon' instead", [], "DetectMappingsWithImages");
+ this.knownImagePaths = knownImagePaths;
}
/**
- * const r = new DetectMappingsWithImages().convert({
+ * const r = new DetectMappingsWithImages(new Set()).convert({
* "mappings": [
* {
* "if": "bicycle_parking=stands",
@@ -407,21 +410,29 @@ export class DetectMappingsWithImages extends DesugaringStep=0
+ const ignore = mapping["#"]?.indexOf(ignoreToken) >= 0
const images = Utils.Dedup(Translations.T(mapping.then)?.ExtractImages() ?? [])
const ctx = `${context}.mappings[${i}]`
if (images.length > 0) {
- if(!ignore){
+ if (!ignore) {
errors.push(`${ctx}: A mapping has an image in the 'then'-clause. Remove the image there and use \`"icon": \` instead. The images found are ${images.join(", ")}. (This check can be turned of by adding "#": "${ignoreToken}" in the mapping, but this is discouraged`)
- }else{
+ } else {
information.push(`${ctx}: Ignored image ${images.join(", ")} in 'then'-clause of a mapping as this check has been disabled`)
+
+ for (const image of images) {
+ if (this.knownImagePaths !== undefined && !this.knownImagePaths.has(image)) {
+ const ctx = context === undefined ? "" : ` in a layer defined in the theme ${context}`
+ errors.push(`Image with path ${image} not found or not attributed; it is used in ${json.id}${ctx}`)
+ }
+ }
+
}
- }else if (ignore){
+ } else if (ignore) {
warnings.push(`${ctx}: unused '${ignoreToken}' - please remove this`)
}
}
- return {
+ return {
errors,
warnings,
information,
@@ -431,10 +442,10 @@ export class DetectMappingsWithImages extends DesugaringStep {
- constructor(layerConfig: LayerConfigJson) {
+ constructor(layerConfig?: LayerConfigJson, knownImagePaths?: Set) {
super("Various validation on tagRenderingConfigs",
- new DetectShadowedMappings( layerConfig),
- new DetectMappingsWithImages()
+ new DetectShadowedMappings(layerConfig),
+ new DetectMappingsWithImages(knownImagePaths)
);
}
}
@@ -446,11 +457,13 @@ export class ValidateLayer extends DesugaringStep {
*/
private readonly _path?: string;
private readonly _isBuiltin: boolean;
+ private knownImagePaths: Set | undefined;
- constructor(path: string, isBuiltin: boolean) {
+ constructor(path: string, isBuiltin: boolean, knownImagePaths: Set) {
super("Doesn't change anything, but emits warnings and errors", [], "ValidateLayer");
this._path = path;
this._isBuiltin = isBuiltin;
+ this.knownImagePaths = knownImagePaths
}
convert(json: LayerConfigJson, context: string): { result: LayerConfigJson; errors: string[]; warnings?: string[], information?: string[] } {
@@ -475,13 +488,13 @@ export class ValidateLayer extends DesugaringStep {
{
// duplicate ids in tagrenderings check
- const duplicates = Utils.Dedup(Utils.Dupiclates( Utils.NoNull((json.tagRenderings ?? []).map(tr => tr["id"]))))
- .filter(dupl => dupl !== "questions")
- if(duplicates.length > 0){
- errors.push("At "+context+": some tagrenderings have a duplicate id: "+duplicates.join(", "))
+ const duplicates = Utils.Dedup(Utils.Dupiclates(Utils.NoNull((json.tagRenderings ?? []).map(tr => tr["id"]))))
+ .filter(dupl => dupl !== "questions")
+ if (duplicates.length > 0) {
+ errors.push("At " + context + ": some tagrenderings have a duplicate id: " + duplicates.join(", "))
}
}
-
+
try {
{
// Some checks for legacy elements
@@ -538,10 +551,10 @@ export class ValidateLayer extends DesugaringStep {
}
}
if (json.tagRenderings !== undefined) {
- const r = new On("tagRenderings", new Each(new ValidateTagRenderings(json))).convert(json, context)
- warnings.push(...(r.warnings??[]))
- errors.push(...(r.errors??[]))
- information.push(...(r.information??[]))
+ const r = new On("tagRenderings", new Each(new ValidateTagRenderings(json, this.knownImagePaths))).convert(json, context)
+ warnings.push(...(r.warnings ?? []))
+ errors.push(...(r.errors ?? []))
+ information.push(...(r.information ?? []))
}
if (json.presets !== undefined) {
diff --git a/UI/Input/ValidatedTextField.ts b/UI/Input/ValidatedTextField.ts
index 048c86dec2..0f871573ca 100644
--- a/UI/Input/ValidatedTextField.ts
+++ b/UI/Input/ValidatedTextField.ts
@@ -547,7 +547,7 @@ class LengthTextField extends TextFieldDef {
constructor() {
super(
- "length", "A geographical length 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\"]"
+ "distance", "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\"]"
)
}
diff --git a/UI/i18n/Translations.ts b/UI/i18n/Translations.ts
index 6a817de9a4..ab3f6e1c8f 100644
--- a/UI/i18n/Translations.ts
+++ b/UI/i18n/Translations.ts
@@ -6,7 +6,7 @@ import CompiledTranslations from "../../assets/generated/CompiledTranslations";
export default class Translations {
- static t = CompiledTranslations.t;
+ static readonly t : typeof CompiledTranslations.t & Readonly = CompiledTranslations.t;
private static knownLanguages = new Set(known_languages.languages)
constructor() {
throw "Translations is static. If you want to intitialize a new translation, use the singular form"
diff --git a/assets/contributors.json b/assets/contributors.json
index e8f356cc56..7b52791431 100644
--- a/assets/contributors.json
+++ b/assets/contributors.json
@@ -1,7 +1,7 @@
{
"contributors": [
{
- "commits": 3912,
+ "commits": 3871,
"contributor": "Pieter Vander Vennet"
},
{
diff --git a/assets/layers/address/address.json b/assets/layers/address/address.json
index ac324ffd7e..2fc720e71a 100644
--- a/assets/layers/address/address.json
+++ b/assets/layers/address/address.json
@@ -118,7 +118,8 @@
"id": "Bangunan ini tidak memiliki nomor rumah",
"es": "Esta edificación no tiene número",
"zh_Hans": "这个建筑物没有门牌号",
- "da": "Denne bygning har intet husnummer"
+ "da": "Denne bygning har intet husnummer",
+ "zh_Hant": "這棟建築沒有門牌"
}
}
]
diff --git a/assets/layers/barrier/barrier.json b/assets/layers/barrier/barrier.json
index 508f0e29f7..8e99da33f9 100644
--- a/assets/layers/barrier/barrier.json
+++ b/assets/layers/barrier/barrier.json
@@ -373,7 +373,7 @@
},
"freeform": {
"key": "maxwidth:physical",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"20",
"map"
@@ -406,7 +406,7 @@
},
"freeform": {
"key": "width:separation",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"21",
"map"
@@ -440,7 +440,7 @@
},
"freeform": {
"key": "width:opening",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"21",
"map"
@@ -474,7 +474,7 @@
},
"freeform": {
"key": "overlap",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"21",
"map"
diff --git a/assets/layers/cafe_pub/cafe_pub.json b/assets/layers/cafe_pub/cafe_pub.json
index 1215b45367..2c77c8d2f1 100644
--- a/assets/layers/cafe_pub/cafe_pub.json
+++ b/assets/layers/cafe_pub/cafe_pub.json
@@ -16,7 +16,8 @@
"amenity=bar",
"amenity=pub",
"amenity=cafe",
- "amenity=biergarten"
+ "amenity=biergarten",
+ "amenity=nightclub"
]
}
},
@@ -94,6 +95,22 @@
"preciseInput": {
"preferredBackground": "map"
}
+ },
+ {
+ "tags": [
+ "amenity=nightclub"
+ ],
+ "title": {
+ "en": "a nightclub or disco",
+ "nl": "een nachtclub of disco"
+ },
+ "description": {
+ "en": "A nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks",
+ "nl": "Een nachtclub met dansvloer, DJ met bijhorende lichteffecten en bar waar men (alcoholische) dranken kan nuttigen"
+ },
+ "preciseInput": {
+ "preferredBackground": "map"
+ }
}
],
"title": {
@@ -209,6 +226,13 @@
"es": "Un espacio abierto donde se sirve cerveza, típico de Alemania"
},
"hideInAnswer": "_country!=de"
+ },
+ {
+ "if": "amenity=nightclub",
+ "then": {
+ "en": "This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks",
+ "nl": "Dit is een nachtclub met dansvloer, DJ met bijhorende lichteffecten en bar waar men (alcoholische) dranken kan nuttigen"
+ }
}
],
"id": "Classification"
@@ -219,6 +243,7 @@
"phone",
"payment-options",
"wheelchair-access",
+ "smoking",
"service:electricity",
"dog-access",
"reviews"
@@ -272,6 +297,10 @@
{
"if": "amenity=cafe",
"then": "circle:white;./assets/layers/cafe_pub/cafe.svg"
+ },
+ {
+ "if": "amenity=nightclub",
+ "then": "circle:white;./assets/layers/cafe_pub/nightclub.svg"
}
]
},
diff --git a/assets/layers/cafe_pub/license_info.json b/assets/layers/cafe_pub/license_info.json
index dd4798197e..9ba0c84577 100644
--- a/assets/layers/cafe_pub/license_info.json
+++ b/assets/layers/cafe_pub/license_info.json
@@ -9,6 +9,16 @@
"https://wiki.openstreetmap.org/wiki/File:Cafe-16.svg"
]
},
+ {
+ "path": "nightclub.svg",
+ "license": "CC0",
+ "authors": [
+ "Osm Carto"
+ ],
+ "sources": [
+ "https://wiki.openstreetmap.org/wiki/File:Nightclub-16.svg"
+ ]
+ },
{
"path": "pub.svg",
"license": "CC0",
diff --git a/assets/layers/cafe_pub/nightclub.svg b/assets/layers/cafe_pub/nightclub.svg
new file mode 100644
index 0000000000..5e34e56312
--- /dev/null
+++ b/assets/layers/cafe_pub/nightclub.svg
@@ -0,0 +1,27 @@
+
+
diff --git a/assets/layers/cycleways_and_roads/cycleways_and_roads.json b/assets/layers/cycleways_and_roads/cycleways_and_roads.json
index 2874b8a36c..8b767a15dd 100644
--- a/assets/layers/cycleways_and_roads/cycleways_and_roads.json
+++ b/assets/layers/cycleways_and_roads/cycleways_and_roads.json
@@ -836,7 +836,7 @@
},
"freeform": {
"key": "width:carriageway",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"20",
"map"
@@ -1260,7 +1260,7 @@
},
"freeform": {
"key": "cycleway:buffer",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"20",
"map"
diff --git a/assets/layers/entrance/entrance.json b/assets/layers/entrance/entrance.json
index 6cb1883c31..d1aaf587e7 100644
--- a/assets/layers/entrance/entrance.json
+++ b/assets/layers/entrance/entrance.json
@@ -338,7 +338,7 @@
},
"freeform": {
"key": "width",
- "type": "length"
+ "type": "distance"
}
}
],
diff --git a/assets/license_info.json b/assets/license_info.json
index 3e657b34d7..c4510d13af 100644
--- a/assets/license_info.json
+++ b/assets/license_info.json
@@ -17,6 +17,22 @@
],
"sources": []
},
+ {
+ "path": "SocialImageBanner.png",
+ "license": "CC0",
+ "authors": [
+ "Pieter Vander Vennet"
+ ],
+ "sources": []
+ },
+ {
+ "path": "SocialImageBanner.svg",
+ "license": "CC0",
+ "authors": [
+ "Pieter Vander Vennet"
+ ],
+ "sources": []
+ },
{
"path": "SocialImageSmall.png",
"license": "CC-BY-SA 4.0",
diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json
index f992a5304d..133544ecf8 100644
--- a/assets/svg/license_info.json
+++ b/assets/svg/license_info.json
@@ -141,16 +141,6 @@
"https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg"
]
},
- {
- "path": "cash.svg",
- "license": "CC-BY 3.0",
- "authors": [
- "Online Web Fonts"
- ],
- "sources": [
- "https://www.onlinewebfonts.com/icon/464494"
- ]
- },
{
"path": "checkbox-empty.svg",
"license": "CC0",
@@ -859,16 +849,6 @@
],
"sources": []
},
- {
- "path": "nfc_card.svg",
- "license": "CC0",
- "authors": [
- "Stijn Wens"
- ],
- "sources": [
- "https://wens.be/free-antwerpenize-bicycle-font"
- ]
- },
{
"path": "no_checkmark.svg",
"license": "CC0; trivial",
@@ -951,16 +931,6 @@
"https://github.com/twitter/twemoji"
]
},
- {
- "path": "payment_card.svg",
- "license": "CC0",
- "authors": [
- " \tMaxi Koichi (maxixam)"
- ],
- "sources": [
- "https://commons.wikimedia.org/wiki/File:Credit_Card_-_The_Noun_Project.svg"
- ]
- },
{
"path": "pencil.svg",
"license": "MIT",
@@ -983,26 +953,6 @@
" https://commons.wikimedia.org/wiki/File:Octicons-pencil.svg"
]
},
- {
- "path": "phone.svg",
- "license": "CC-BY 3.0",
- "authors": [
- "@ tyskrat"
- ],
- "sources": [
- "https://www.onlinewebfonts.com/icon/1059"
- ]
- },
- {
- "path": "phone.svg",
- "license": "CC-BY 3.0",
- "authors": [
- "@ tyskrat"
- ],
- "sources": [
- "https://www.onlinewebfonts.com/icon/1059"
- ]
- },
{
"path": "pin.svg",
"license": "CC0; trivial",
@@ -1151,18 +1101,6 @@
"https://phabricator.wikimedia.org/diffusion/GOJU/browse/master/AUTHORS.txt"
]
},
- {
- "path": "send_email.svg",
- "license": "CC0; trivial",
- "authors": [],
- "sources": []
- },
- {
- "path": "send_email.svg",
- "license": "CC0; trivial",
- "authors": [],
- "sources": []
- },
{
"path": "share.svg",
"license": "CC0; trivial",
@@ -1175,16 +1113,6 @@
"authors": [],
"sources": []
},
- {
- "path": "smartphone.svg",
- "license": "CC-BY 3.0",
- "authors": [
- "To Uyen"
- ],
- "sources": [
- "https://commons.wikimedia.org/wiki/File:Smartphone_icon_-_Noun_Project_283536.svg"
- ]
- },
{
"path": "speech_bubble.svg",
"license": "CC-BY 4.0",
diff --git a/assets/svg/cash.svg b/assets/tagRenderings/cash.svg
similarity index 100%
rename from assets/svg/cash.svg
rename to assets/tagRenderings/cash.svg
diff --git a/assets/tagRenderings/icons.json b/assets/tagRenderings/icons.json
index 3abd316843..6a0d786d78 100644
--- a/assets/tagRenderings/icons.json
+++ b/assets/tagRenderings/icons.json
@@ -5,6 +5,7 @@
"phonelink",
"emaillink",
"wikipedialink",
+ "smokingicon",
"osmlink",
"sharelink"
],
@@ -20,6 +21,7 @@
},
"mappings": [
{
+ "#": "ignore-image-in-then",
"if": "wikipedia=",
"then": "
"
}
@@ -59,13 +61,27 @@
]
},
"phonelink": {
- "render": "
",
+ "render": "
",
"condition": "phone~*"
},
"emaillink": {
- "render": "
",
+ "render": "
",
"condition": "email~*"
},
+ "smokingicon": {
+ "mappings": [
+ {
+ "#": "ignore-image-in-then",
+ "if": "smoking=no",
+ "then": "
"
+ },
+ {
+ "#": "ignore-image-in-then",
+ "if": "smoking=yes",
+ "then": "
"
+ }
+ ]
+ },
"osmlink": {
"render": "
",
"mappings": [
@@ -74,6 +90,7 @@
"then": ""
},
{
+ "#": "ignore-image-in-then",
"if": "_backend~*",
"then": "
"
}
diff --git a/assets/tagRenderings/license_info.json b/assets/tagRenderings/license_info.json
new file mode 100644
index 0000000000..c65bd6f938
--- /dev/null
+++ b/assets/tagRenderings/license_info.json
@@ -0,0 +1,96 @@
+[
+ {
+ "path": "cash.svg",
+ "license": "CC-BY 3.0",
+ "authors": [
+ "Online Web Fonts"
+ ],
+ "sources": [
+ "https://www.onlinewebfonts.com/icon/464494"
+ ]
+ },
+ {
+ "path": "nfc_card.svg",
+ "license": "CC0",
+ "authors": [
+ "Stijn Wens"
+ ],
+ "sources": [
+ "https://wens.be/free-antwerpenize-bicycle-font"
+ ]
+ },
+ {
+ "path": "no_smoking.svg",
+ "license": "CC0",
+ "authors": [
+ "AIGA"
+ ],
+ "sources": [
+ "https://upload.wikimedia.org/wikipedia/commons/6/6b/No_Smoking.svg",
+ "https://www.aiga.org/content.cfm/symbol-signs"
+ ]
+ },
+ {
+ "path": "payment_card.svg",
+ "license": "CC0",
+ "authors": [
+ " \tMaxi Koichi (maxixam)"
+ ],
+ "sources": [
+ "https://commons.wikimedia.org/wiki/File:Credit_Card_-_The_Noun_Project.svg"
+ ]
+ },
+ {
+ "path": "phone.svg",
+ "license": "CC-BY 3.0",
+ "authors": [
+ "@ tyskrat"
+ ],
+ "sources": [
+ "https://www.onlinewebfonts.com/icon/1059"
+ ]
+ },
+ {
+ "path": "phone.svg",
+ "license": "CC-BY 3.0",
+ "authors": [
+ "@ tyskrat"
+ ],
+ "sources": [
+ "https://www.onlinewebfonts.com/icon/1059"
+ ]
+ },
+ {
+ "path": "send_email.svg",
+ "license": "CC0; trivial",
+ "authors": [],
+ "sources": []
+ },
+ {
+ "path": "send_email.svg",
+ "license": "CC0; trivial",
+ "authors": [],
+ "sources": []
+ },
+ {
+ "path": "smartphone.svg",
+ "license": "CC-BY 3.0",
+ "authors": [
+ "To Uyen"
+ ],
+ "sources": [
+ "https://commons.wikimedia.org/wiki/File:Smartphone_icon_-_Noun_Project_283536.svg"
+ ]
+ },
+ {
+ "path": "smoking.svg",
+ "license": "CC0",
+ "authors": [
+ "Wiki-User03",
+ "ZooFari"
+ ],
+ "sources": [
+ "https://commons.wikimedia.org/wiki/File:Smoking_pictogram_(black).svg"
+ ]
+ }
+]
\ No newline at end of file
diff --git a/assets/svg/nfc_card.svg b/assets/tagRenderings/nfc_card.svg
similarity index 100%
rename from assets/svg/nfc_card.svg
rename to assets/tagRenderings/nfc_card.svg
diff --git a/assets/tagRenderings/no_smoking.svg b/assets/tagRenderings/no_smoking.svg
new file mode 100644
index 0000000000..b0a1161087
--- /dev/null
+++ b/assets/tagRenderings/no_smoking.svg
@@ -0,0 +1,160 @@
+
+
+
+
\ No newline at end of file
diff --git a/assets/svg/payment_card.svg b/assets/tagRenderings/payment_card.svg
similarity index 100%
rename from assets/svg/payment_card.svg
rename to assets/tagRenderings/payment_card.svg
diff --git a/assets/svg/phone.svg b/assets/tagRenderings/phone.svg
similarity index 100%
rename from assets/svg/phone.svg
rename to assets/tagRenderings/phone.svg
diff --git a/assets/tagRenderings/questions.json b/assets/tagRenderings/questions.json
index d1dd19d588..862a64043a 100644
--- a/assets/tagRenderings/questions.json
+++ b/assets/tagRenderings/questions.json
@@ -745,7 +745,7 @@
{
"if": "payment:cash=yes",
"ifnot": "payment:cash=no",
- "icon": "./assets/svg/cash.svg",
+ "icon": "./assets/tagRenderings/cash.svg",
"then": {
"en": "Cash is accepted here",
"nl": "Cash geld wordt hier aanvaard",
@@ -773,7 +773,7 @@
{
"if": "payment:cards=yes",
"ifnot": "payment:cards=no",
- "icon": "./assets/svg/payment_card.svg",
+ "icon": "./assets/tagRenderings/payment_card.svg",
"then": {
"en": "Payment cards are accepted here",
"nl": "Betalen met bankkaarten kan hier",
@@ -807,7 +807,7 @@
{
"if": "payment:app=yes",
"ifnot": "payment:app=no",
- "icon": "./assets/svg/smartphone.svg",
+ "icon": "./assets/tagRenderings/smartphone.svg",
"then": {
"en": "Payment is done using a dedicated app",
"nl": "Betalen via een app van het netwerk",
@@ -828,7 +828,7 @@
{
"if": "payment:membership_card=yes",
"ifnot": "payment:membership_card=no",
- "icon": "./assets/svg/nfc_card.svg",
+ "icon": "./assets/tagRenderings/nfc_card.svg",
"then": {
"en": "Payment is done using a membership card",
"nl": "Betalen via een lidkaart van het netwerk",
@@ -1031,5 +1031,40 @@
}
}
]
+ },
+ "smoking": {
+ "question": {
+ "en": "Is smoking allowed at {title()}?"
+ },
+ "#condition": "Based on https://en.wikipedia.org/wiki/List_of_smoking_bans",
+ "condition": "_country!~al|be",
+ "mappings": [
+ {
+ "if": "smoking=yes",
+ "icon": {
+ "path": "./assets/tagRenderings/smoking.svg",
+ "size": "small"
+ },
+ "then": {
+ "en": "Smoking is allowed"
+ }
+ },
+ {
+ "if": "smoking=no",
+ "icon": {
+ "path": "./assets/tagRenderings/no_smoking.svg",
+ "size": "small"
+ },
+ "then": {
+ "en": "Smoking is not allowed"
+ }
+ },
+ {
+ "if": "smoking=outside",
+ "then": {
+ "en": "Smoking is allowed outside."
+ }
+ }
+ ]
}
}
\ No newline at end of file
diff --git a/assets/svg/send_email.svg b/assets/tagRenderings/send_email.svg
similarity index 100%
rename from assets/svg/send_email.svg
rename to assets/tagRenderings/send_email.svg
diff --git a/assets/svg/smartphone.svg b/assets/tagRenderings/smartphone.svg
similarity index 100%
rename from assets/svg/smartphone.svg
rename to assets/tagRenderings/smartphone.svg
diff --git a/assets/tagRenderings/smoking.svg b/assets/tagRenderings/smoking.svg
new file mode 100644
index 0000000000..f9d91d82b8
--- /dev/null
+++ b/assets/tagRenderings/smoking.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/assets/themes/mapcomplete-changes/mapcomplete-changes.json b/assets/themes/mapcomplete-changes/mapcomplete-changes.json
index 78d8fd8800..cfa960cdf4 100644
--- a/assets/themes/mapcomplete-changes/mapcomplete-changes.json
+++ b/assets/themes/mapcomplete-changes/mapcomplete-changes.json
@@ -1,13 +1,24 @@
{
"id": "mapcomplete-changes",
"title": {
- "en": "Changes made with MapComplete"
+ "en": "Changes made with MapComplete",
+ "de": "Änderungen mit MapComplete",
+ "es": "Cambios hechos con MapComplete",
+ "nb_NO": "Endringer utført med MapComplete",
+ "nl": "Wijzigingen gemaakt met MapComplete"
},
"shortDescription": {
- "en": "Shows changes made by MapComplete"
+ "en": "Shows changes made by MapComplete",
+ "de": "Zeigt Änderungen von MapComplete",
+ "es": "Muestra los cambios hechos por MapComplete",
+ "nb_NO": "Vis endringer utført med MapComplete",
+ "nl": "Toont wijzigingen gemaakt met MapComplete"
},
"description": {
- "en": "This maps shows all the changes made with MapComplete"
+ "en": "This maps shows all the changes made with MapComplete",
+ "de": "Diese Karte zeigt alle Änderungen die mit MapComplete gemacht wurden",
+ "es": "Este mapa muestra todos los cambios hechos con MapComplete",
+ "nl": "Deze kaart toont alle wijzigingen die met MapComplete werden gemaakt"
},
"maintainer": "",
"icon": "./assets/svg/logo.svg",
@@ -22,7 +33,10 @@
{
"id": "mapcomplete-changes",
"name": {
- "en": "Changeset centers"
+ "en": "Changeset centers",
+ "de": "Schwerpunkte von Änderungssätzen",
+ "es": "Centros de conjuntos de cambios",
+ "nb_NO": "Endringssettsenter"
},
"minzoom": 0,
"source": {
@@ -36,35 +50,55 @@
],
"title": {
"render": {
- "en": "Changeset for {theme}"
+ "en": "Changeset for {theme}",
+ "de": "Änderungen für {theme}",
+ "es": "Conjunto de cambios para {theme}",
+ "nb_NO": "Endringssett for {theme}",
+ "nl": "Wijzigingset voor {theme}"
}
},
"description": {
- "en": "Shows all MapComplete changes"
+ "en": "Shows all MapComplete changes",
+ "de": "Zeigt alle MapComplete Änderungen",
+ "es": "Muestra todos los cambios de MapComplete",
+ "nl": "Toont alle wijzigingen met MapComplete"
},
"tagRenderings": [
{
"id": "render_id",
"render": {
- "en": "Changeset {id}"
+ "en": "Changeset {id}",
+ "de": "Änderung {id}",
+ "es": "Conjunto de cambios {id}",
+ "nb_NO": "Endringssett {id}",
+ "nl": "Wijzigingset {id}"
}
},
{
"id": "contributor",
"render": {
- "en": "Change made by {_last_edit:contributor}"
+ "en": "Change made by {_last_edit:contributor}",
+ "de": "Änderung wurde von {_last_edit:contributor} gemacht",
+ "es": "Cambio hecho por {_last_edit:contributor}",
+ "nl": "Wijziging gemaakt door {_last_edit:contributor}"
}
},
{
"id": "theme",
"render": {
- "en": "Change with theme {theme}"
+ "en": "Change with theme {theme}",
+ "de": "Änderung mit Thema {theme}",
+ "es": "Cambio con tema {theme}",
+ "nl": "Wijziging met thema {theme}"
},
"mappings": [
{
"if": "theme~http.*",
"then": {
- "en": "Change with unofficial theme {theme}"
+ "en": "Change with unofficial theme {theme}",
+ "de": "Änderung mit inoffiziellem Thema {theme}",
+ "es": "Cambio con tema no oficial {theme}",
+ "nl": "Wijziging met officieus thema {theme}"
}
}
]
@@ -336,7 +370,11 @@
}
],
"question": {
- "en": "Themename contains {search}"
+ "en": "Themename contains {search}",
+ "de": "Themenname enthält {search}",
+ "es": "Nombre del tema contiene {search}",
+ "nb_NO": "Temanavn inneholder {search}",
+ "nl": "Themanaam bevat {search}"
}
}
]
@@ -352,7 +390,10 @@
}
],
"question": {
- "en": "Made by contributor {search}"
+ "en": "Made by contributor {search}",
+ "de": "Erstellt von {search}",
+ "es": "Hecho por contributor/a {search}",
+ "nl": "Gemaakt door bijdrager {search}"
}
}
]
@@ -368,7 +409,10 @@
}
],
"question": {
- "en": "Not made by contributor {search}"
+ "en": "Not made by contributor {search}",
+ "de": "Nicht erstellt von {search}",
+ "es": "No hecho por contributor/a {search}",
+ "nl": "Niet gemaakt door bijdrager {search}"
}
}
]
@@ -383,7 +427,10 @@
{
"id": "link_to_more",
"render": {
- "en": "More statistics can be found here"
+ "en": "More statistics can be found here",
+ "de": "Weitere Statistiken finden Sie hier",
+ "es": "Se pueden encontrar más estadísticas aquí",
+ "nl": "Meer statistieken kunnen hier gevonden worden"
}
},
{
diff --git a/assets/themes/sidewalks/sidewalks.json b/assets/themes/sidewalks/sidewalks.json
index 48114ad57d..918d09bf51 100644
--- a/assets/themes/sidewalks/sidewalks.json
+++ b/assets/themes/sidewalks/sidewalks.json
@@ -126,7 +126,7 @@
"condition": "sidewalk:left|right=yes",
"freeform": {
"key": "sidewalk:left|right:width",
- "type": "length",
+ "type": "distance",
"helperArgs": [
"21",
"map"
diff --git a/assets/translators.json b/assets/translators.json
index 05def3dbe0..b3f079df4e 100644
--- a/assets/translators.json
+++ b/assets/translators.json
@@ -29,7 +29,7 @@
"contributor": "Iago"
},
{
- "commits": 22,
+ "commits": 23,
"contributor": "Supaplex"
},
{
diff --git a/langs/ca.json b/langs/ca.json
index 4d81684387..7c2b0f1056 100644
--- a/langs/ca.json
+++ b/langs/ca.json
@@ -548,9 +548,6 @@
"date": {
"description": "Una data, començant per l'any"
},
- "decimal": {
- "description": "Un número"
- },
"direction": {
"description": "Una orientació"
},
diff --git a/langs/da.json b/langs/da.json
index 4119962395..0f2e9ce1ec 100644
--- a/langs/da.json
+++ b/langs/da.json
@@ -634,9 +634,6 @@
"date": {
"description": "En dato, der starter med årstallet"
},
- "decimal": {
- "description": "Et tal"
- },
"direction": {
"description": "En retning"
},
diff --git a/langs/de.json b/langs/de.json
index eed4dc34c7..8e07c60f85 100644
--- a/langs/de.json
+++ b/langs/de.json
@@ -456,8 +456,10 @@
"sendReason": "Ich habe Ihnen diese Nachricht geschickt, weil {sender} mich gebeten hat, diese mit {cmd}
zu senden"
},
"documentation": {
+ "argid": "Die ID einer {list} oder {list_end}, für welche die Dokumente benötigt werden. Alternativ können Sie auch eine von {coded_list} schreiben, um die verfügbaren IDs zu sehen.",
"didYouMean": " Vielleicht meinten Sie einen von: ",
"docs": "Ruft die Dokumentation zu einer MapComplete-Ebene, einem Thema oder einem URL-Parameter ab",
+ "noIdIntro": "Geben Sie eine ID an, um weitere Informationen über ein MapComplete-Programmierelement zu erhalten. Bekannte Typen sind {list}",
"notFound": "Kein {singular} mit Namen {id}
gefunden.",
"urlParam": "URL-Parameter {id}
"
},
@@ -753,9 +755,6 @@
"date": {
"description": "Ein Datum, beginnend mit der Jahreszahl"
},
- "decimal": {
- "description": "Eine Zahl"
- },
"direction": {
"description": "Eine Himmelsrichtung"
},
diff --git a/langs/en.json b/langs/en.json
index 6cd0494e12..0eeafcb6ab 100644
--- a/langs/en.json
+++ b/langs/en.json
@@ -828,12 +828,12 @@
"date": {
"description": "A date, starting with the year"
},
- "decimal": {
- "description": "A number"
- },
"direction": {
"description": "An orientation"
},
+ "distance": {
+ "description": "A distance in meter"
+ },
"email": {
"description": "email-adres",
"feedback": "This is not a valid email address",
@@ -846,9 +846,6 @@
"int": {
"description": "a whole number"
},
- "length": {
- "description": "a length measurement in meter"
- },
"nat": {
"description": "a positive, whole number or zero",
"mustBePositive": "This number should be positive",
diff --git a/langs/es.json b/langs/es.json
index 0c21fd6af6..66e4fe6a80 100644
--- a/langs/es.json
+++ b/langs/es.json
@@ -516,9 +516,6 @@
"deactivate": "Deshabilitar los botones de traducción"
},
"validation": {
- "decimal": {
- "description": "Un número"
- },
"direction": {
"description": "Una orientación"
},
diff --git a/langs/id.json b/langs/id.json
index fac405153e..c8011e04b5 100644
--- a/langs/id.json
+++ b/langs/id.json
@@ -144,9 +144,6 @@
"date": {
"description": "Tanggal, dimulai dari tahun"
},
- "decimal": {
- "description": "Nomor"
- },
"direction": {
"description": "Orientasi"
},
diff --git a/langs/layers/en.json b/langs/layers/en.json
index e052bccbc0..c582615c4d 100644
--- a/langs/layers/en.json
+++ b/langs/layers/en.json
@@ -1274,6 +1274,10 @@
"2": {
"description": "A cafe to drink tea, coffee or an alcoholical bevarage in a quiet environment",
"title": "a cafe"
+ },
+ "3": {
+ "description": "A nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks",
+ "title": "a nightclub or disco"
}
},
"tagRenderings": {
@@ -1293,6 +1297,9 @@
},
"4": {
"then": "An open space where beer is served, typically seen in Germany"
+ },
+ "5": {
+ "then": "This is a nightclub or disco with a focus on dancing, music by a DJ with accompanying light show and a bar to get (alcoholic) drinks"
}
},
"question": "What kind of cafe is this?"
diff --git a/langs/layers/nl.json b/langs/layers/nl.json
index 305f85991b..a751b75789 100644
--- a/langs/layers/nl.json
+++ b/langs/layers/nl.json
@@ -1280,6 +1280,10 @@
"2": {
"description": "Dit is een cafe - een plaats waar men rustig kan zitten om een thee, koffie of alcoholische drank te nuttigen.",
"title": "een café"
+ },
+ "3": {
+ "description": "Een nachtclub met dansvloer, DJ met bijhorende lichteffecten en bar waar men (alcoholische) dranken kan nuttigen",
+ "title": "een nachtclub of disco"
}
},
"tagRenderings": {
@@ -1299,6 +1303,9 @@
},
"4": {
"then": "Een open ruimte waar bier geserveerd wordt. Typisch in Duitsland"
+ },
+ "5": {
+ "then": "Dit is een nachtclub met dansvloer, DJ met bijhorende lichteffecten en bar waar men (alcoholische) dranken kan nuttigen"
}
},
"question": "Welk soort café is dit?"
diff --git a/langs/layers/zh_Hant.json b/langs/layers/zh_Hant.json
index 6a0ea50c11..f9a2f96070 100644
--- a/langs/layers/zh_Hant.json
+++ b/langs/layers/zh_Hant.json
@@ -5,6 +5,13 @@
"tagRenderings": {
"fixme": {
"question": "這裡需要修什麼?請直接解釋"
+ },
+ "housenumber": {
+ "mappings": {
+ "0": {
+ "then": "這棟建築沒有門牌"
+ }
+ }
}
}
},
diff --git a/langs/nb_NO.json b/langs/nb_NO.json
index a521d3409f..c08fb9ce17 100644
--- a/langs/nb_NO.json
+++ b/langs/nb_NO.json
@@ -480,9 +480,6 @@
"date": {
"description": "En dato, som starter med året"
},
- "decimal": {
- "description": "Et tall"
- },
"direction": {
"description": "En retning"
},
diff --git a/langs/nl.json b/langs/nl.json
index 874b900cda..16d2729f52 100644
--- a/langs/nl.json
+++ b/langs/nl.json
@@ -753,12 +753,12 @@
"date": {
"description": "Een datum (beginnend met het jaar)"
},
- "decimal": {
- "description": "Een getal"
- },
"direction": {
"description": "Een orientatie"
},
+ "distance": {
+ "description": "Een afstand in meter"
+ },
"email": {
"description": "email-adres",
"feedback": "Dit is geen geldig email-adres",
diff --git a/langs/shared-questions/en.json b/langs/shared-questions/en.json
index fce4c92175..944c5d5cb3 100644
--- a/langs/shared-questions/en.json
+++ b/langs/shared-questions/en.json
@@ -91,6 +91,20 @@
},
"question": "Does this amenity have electrical outlets, available to customers when they are inside?"
},
+ "smoking": {
+ "mappings": {
+ "0": {
+ "then": "Smoking is allowed"
+ },
+ "1": {
+ "then": "Smoking is not allowed"
+ },
+ "2": {
+ "then": "Smoking is allowed outside."
+ }
+ },
+ "question": "Is smoking allowed at {title()}?"
+ },
"website": {
"question": "What is the website of {title()}?"
},
diff --git a/package.json b/package.json
index c4057fbc32..b9dc215605 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
"main": "index.js",
"scripts": {
"start": "npm run generate:layeroverview && npm run strt",
- "strt": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve *.html UI/** Logic/** assets/*.json assets/svg/* assets/generated/* assets/layers/*/*.svg assets/layers/*/*/*/*.svg assets/layers/*/*.jpg assets/layers/*/*.png assets/layers/*/*.css assets/tagRenderings/*.json assets/themes/*/*.svg assets/themes/*/*.ttf assets/themes/*/*/*.ttf assets/themes/*/*.otf assets/themes/*/*/*.otf assets/themes/*/*.css assets/themes/*/*.jpg assets/themes/*/*.woff assets/themes/*/*.png vendor/* vendor/*/*",
+ "strt": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve *.html UI/** Logic/** assets/*.json assets/svg/* assets/generated/* assets/layers/*/*.svg assets/layers/*/*/*/*.svg assets/layers/*/*.jpg assets/layers/*/*.png assets/layers/*/*.css assets/tagRenderings/*.json assets/themes/*/*.svg assets/themes/*/*.ttf assets/themes/*/*/*.ttf assets/themes/*/*.otf assets/themes/*/*/*.otf assets/themes/*/*.css assets/themes/*/*.jpg assets/themes/*/*.woff assets/themes/*/*.png vendor/* vendor/*/* assets/tagRenderings/*.svg",
"strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html",
"watch:css": "tailwindcss -i index.css -o css/index-tailwind-output.css --watch",
"generate:css": "tailwindcss -i index.css -o css/index-tailwind-output.css",
diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts
index 70c70739bf..a87b3ade51 100644
--- a/scripts/generateLayerOverview.ts
+++ b/scripts/generateLayerOverview.ts
@@ -4,7 +4,12 @@ import * as licenses from "../assets/generated/license_info.json"
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
import Constants from "../Models/Constants";
-import {PrevalidateTheme, ValidateLayer, ValidateThemeAndLayers} from "../Models/ThemeConfig/Conversion/Validation";
+import {
+ PrevalidateTheme,
+ ValidateLayer,
+ ValidateTagRenderings,
+ ValidateThemeAndLayers
+} from "../Models/ThemeConfig/Conversion/Validation";
import {Translation} from "../UI/i18n/Translation";
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
import * as questions from "../assets/tagRenderings/questions.json";
@@ -14,24 +19,25 @@ import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer";
import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme";
import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion";
import {Utils} from "../Utils";
+import {And} from "../Logic/Tags/And";
// This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
// It spits out an overview of those to be used to load them
class LayerOverviewUtils {
- writeSmallOverview(themes: { id: string, title: any, shortDescription: any, icon: string, hideFromOverview: boolean, mustHaveLanguage: boolean, layers: (LayerConfigJson | string | {builtin})[] }[]) {
+ writeSmallOverview(themes: { id: string, title: any, shortDescription: any, icon: string, hideFromOverview: boolean, mustHaveLanguage: boolean, layers: (LayerConfigJson | string | { builtin })[] }[]) {
const perId = new Map();
for (const theme of themes) {
-
- const keywords : {}[] = []
+
+ const keywords: {}[] = []
for (const layer of (theme.layers ?? [])) {
- const l = layer;
+ const l = layer;
keywords.push({"*": l.id})
keywords.push(l.title)
keywords.push(l.description)
}
-
+
const data = {
id: theme.id,
title: theme.title,
@@ -77,16 +83,19 @@ class LayerOverviewUtils {
writeFileSync(`./assets/generated/layers/${layer.id}.json`, JSON.stringify(layer, null, " "), "UTF8");
}
- getSharedTagRenderings(): Map {
+ getSharedTagRenderings(knownImagePaths: Set): Map {
const dict = new Map();
-
+
+ const validator = new ValidateTagRenderings(undefined, knownImagePaths);
for (const key in questions["default"]) {
if (key === "id") {
continue
}
questions[key].id = key;
questions[key]["source"] = "shared-questions"
- dict.set(key, questions[key])
+ const config = questions[key]
+ validator.convertStrict(config, "generate-layer-overview:tagRenderings/questions.json:"+key)
+ dict.set(key, config)
}
for (const key in icons["default"]) {
if (key === "id") {
@@ -96,7 +105,9 @@ class LayerOverviewUtils {
continue
}
icons[key].id = key;
- dict.set(key, icons[key])
+ const config = icons[key]
+ validator.convertStrict(config, "generate-layer-overview:tagRenderings/icons.json:"+key)
+ dict.set(key,config)
}
dict.forEach((value, key) => {
@@ -114,9 +125,9 @@ class LayerOverviewUtils {
.filter(path => path.endsWith(".svg"))
.filter(path => !path.startsWith("./assets/generated"))
let errCount = 0;
- const exempt = ["assets/SocialImageTemplate.svg","assets/SocialImageTemplateWide.svg","assets/SocialImageBanner.svg", "assets/svg/osm-logo.svg"];
+ const exempt = ["assets/SocialImageTemplate.svg", "assets/SocialImageTemplateWide.svg", "assets/SocialImageBanner.svg", "assets/svg/osm-logo.svg"];
for (const path of allSvgs) {
- if(exempt.some(p => "./"+p === path)) {
+ if (exempt.some(p => "./" + p === path)) {
continue
}
@@ -128,7 +139,7 @@ class LayerOverviewUtils {
throw "A core SVG is actually a PNG. Don't do this!"
}
}
- if(contents.indexOf("0){
+ if (contents.indexOf(" 0) {
console.warn("The SVG at " + path + " contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path")
errCount++;
@@ -183,7 +194,7 @@ class LayerOverviewUtils {
// At the same time, an index of available layers is built.
console.log(" ---------- VALIDATING BUILTIN LAYERS ---------")
- const sharedTagRenderings = this.getSharedTagRenderings();
+ const sharedTagRenderings = this.getSharedTagRenderings(knownImagePaths);
const layerFiles = ScriptUtils.getLayerFiles();
const sharedLayers = new Map()
const state: DesugaringContext = {
@@ -194,7 +205,12 @@ 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(sharedLayerJson.path, true);
+
+ if(fixed.source.osmTags["and"] === undefined){
+ fixed.source.osmTags = {"and": [fixed.source.osmTags]}
+ }
+
+ const validator = new ValidateLayer(sharedLayerJson.path, true, knownImagePaths);
validator.convertStrict(fixed, context)
if (sharedLayers.has(fixed.id)) {
@@ -208,25 +224,25 @@ class LayerOverviewUtils {
}
return sharedLayers;
}
-
- private static publicLayerIdsFrom(themefiles: LayoutConfigJson[]): Set{
+
+ private static publicLayerIdsFrom(themefiles: LayoutConfigJson[]): Set {
const publicLayers = [].concat(...themefiles
.filter(th => !th.hideFromOverview)
.map(th => th.layers))
const publicLayerIds = new Set()
for (const publicLayer of publicLayers) {
- if(typeof publicLayer === "string"){
+ if (typeof publicLayer === "string") {
publicLayerIds.add(publicLayer)
continue
}
- if(publicLayer["builtin"] !== undefined){
+ if (publicLayer["builtin"] !== undefined) {
const bi = publicLayer["builtin"]
- if(typeof bi === "string"){
+ if (typeof bi === "string") {
publicLayerIds.add(bi)
continue
}
- bi.forEach(id=>publicLayerIds.add(id))
+ bi.forEach(id => publicLayerIds.add(id))
continue
}
publicLayerIds.add(publicLayer.id)
@@ -243,7 +259,7 @@ class LayerOverviewUtils {
const convertState: DesugaringContext = {
sharedLayers,
- tagRenderings: this.getSharedTagRenderings(),
+ tagRenderings: this.getSharedTagRenderings(knownImagePaths),
publicLayers
}
for (const themeInfo of themeFiles) {
@@ -251,20 +267,20 @@ class LayerOverviewUtils {
const themePath = themeInfo.path
new PrevalidateTheme().convertStrict(themeFile, themePath)
- try{
-
+ try {
+
themeFile = new PrepareTheme(convertState).convertStrict(themeFile, themePath)
-
- if(knownImagePaths === undefined){
+
+ if (knownImagePaths === undefined) {
throw "Could not load known images/licenses"
}
new ValidateThemeAndLayers(knownImagePaths, themePath, true, convertState.tagRenderings)
.convertStrict(themeFile, themePath)
-
+
this.writeTheme(themeFile)
fixed.set(themeFile.id, themeFile)
- }catch(e){
- console.error("ERROR: could not prepare theme "+themePath+" due to "+e)
+ } catch (e) {
+ console.error("ERROR: could not prepare theme " + themePath + " due to " + e)
throw e;
}
}
diff --git a/scripts/generateLicenseInfo.ts b/scripts/generateLicenseInfo.ts
index bb8e77cea8..ea129440b6 100644
--- a/scripts/generateLicenseInfo.ts
+++ b/scripts/generateLicenseInfo.ts
@@ -2,6 +2,7 @@ import {existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync} from "fs
import SmallLicense from "../Models/smallLicense";
import ScriptUtils from "./ScriptUtils";
+const prompt = require('prompt-sync')();
function validateLicenseInfo(l : SmallLicense){
l.sources.map(s => new URL(s))
@@ -55,7 +56,6 @@ function missingLicenseInfos(licenseInfos: SmallLicense[], allIcons: string[]) {
return missing;
}
-const prompt = require('prompt-sync')();
const knownLicenses = new Map()
knownLicenses.set("me", {
@@ -64,45 +64,36 @@ knownLicenses.set("me", {
license: "CC0",
sources: []
})
-
knownLicenses.set("streetcomplete", {
authors: ["Tobias Zwick (westnordost)"],
path: undefined,
license: "CC0",
sources: ["https://github.com/streetcomplete/StreetComplete/tree/master/res/graphics", "https://f-droid.org/packages/de.westnordost.streetcomplete/"]
})
-
-
knownLicenses.set("t", {
authors: [],
path: undefined,
license: "CC0; trivial",
sources: []
})
-
knownLicenses.set("na", {
authors: [],
path: undefined,
license: "CC0",
sources: []
})
-
knownLicenses.set("tv", {
authors: ["Toerisme Vlaanderen"],
path: undefined,
license: "CC0",
sources: ["https://toerismevlaanderen.be/pinjepunt","https://mapcomplete.osm.be/toerisme_vlaanderenn"]
})
-
knownLicenses.set("tvf", {
authors: ["Jo De Baerdemaeker "],
path: undefined,
license: "All rights reserved",
sources: ["https://www.studiotype.be/fonts/flandersart"]
})
-
-
-
knownLicenses.set("twemoji", {
authors: ["Twemoji"],
path: undefined,
@@ -154,7 +145,7 @@ function createLicenseInfoFor(path): void {
function cleanLicenseInfo(allPaths: string[], allLicenseInfos: SmallLicense[]) {
// Read the license info file from the generated assets, creates a compiled license info in every directory
// Note: this removes all the old license infos
- for (const licensePath of licensePaths) {
+ for (const licensePath of allPaths) {
unlinkSync(licensePath)
}
@@ -219,10 +210,13 @@ function queryMissingLicenses(missingLicenses: string[]) {
* Creates the humongous license_info in the generated assets, containing all licenses with a path relative to the root
* @param licensePaths
*/
-function createFullLicenseOverview(licensePaths) {
+function createFullLicenseOverview(licensePaths: string[]) {
const allLicenses: SmallLicense[] = []
for (const licensePath of licensePaths) {
+ if(!existsSync(licensePath)){
+ continue
+ }
const licenses = JSON.parse(readFileSync(licensePath, "UTF-8"))
for (const license of licenses) {
validateLicenseInfo(license)
@@ -235,52 +229,54 @@ function createFullLicenseOverview(licensePaths) {
writeFileSync("./assets/generated/license_info.json", JSON.stringify(allLicenses, null, " "))
}
-console.log("Checking and compiling license info")
-
-if (!existsSync("./assets/generated")) {
- mkdirSync("./assets/generated")
-}
-
-
-let contents = ScriptUtils.readDirRecSync("./assets")
- .filter(entry => entry.indexOf("./assets/generated") != 0)
-let licensePaths = contents.filter(entry => entry.indexOf("license_info.json") >= 0)
-let licenseInfos = generateLicenseInfos(licensePaths);
-
-
-
-const artwork = contents.filter(pth => pth.match(/(.svg|.png|.jpg|.ttf|.otf|.woff)$/i) != null)
-const missingLicenses = missingLicenseInfos(licenseInfos, artwork)
-if (process.argv.indexOf("--prompt") >= 0 || process.argv.indexOf("--query") >= 0) {
- queryMissingLicenses(missingLicenses)
- contents = ScriptUtils.readDirRecSync("./assets")
+function main(args: string[]){
+
+ console.log("Checking and compiling license info")
+
+ if (!existsSync("./assets/generated")) {
+ mkdirSync("./assets/generated")
+ }
+
+
+ let contents = ScriptUtils.readDirRecSync("./assets")
.filter(entry => entry.indexOf("./assets/generated") != 0)
- licensePaths = contents.filter(entry => entry.indexOf("license_info.json") >= 0)
- licenseInfos = generateLicenseInfos(licensePaths);
-}
-
-const invalidLicenses = licenseInfos.filter(l => (l.license ?? "") === "").map(l => `License for artwork ${l.path} is empty string or undefined`)
-for (const licenseInfo of licenseInfos) {
- for (const source of licenseInfo.sources) {
- if (source == "") {
- invalidLicenses.push("Invalid license: empty string in " + JSON.stringify(licenseInfo))
- }
- try {
- new URL(source);
- } catch {
- invalidLicenses.push("Not a valid URL: " + source)
+ let licensePaths = contents.filter(entry => entry.indexOf("license_info.json") >= 0)
+ let licenseInfos = generateLicenseInfos(licensePaths);
+
+
+
+ const artwork = contents.filter(pth => pth.match(/(.svg|.png|.jpg|.ttf|.otf|.woff)$/i) != null)
+ const missingLicenses = missingLicenseInfos(licenseInfos, artwork)
+ if (args.indexOf("--prompt") >= 0 || args.indexOf("--query") >= 0) {
+ queryMissingLicenses(missingLicenses)
+ return main([])
+ }
+
+ const invalidLicenses = licenseInfos.filter(l => (l.license ?? "") === "").map(l => `License for artwork ${l.path} is empty string or undefined`)
+ for (const licenseInfo of licenseInfos) {
+ for (const source of licenseInfo.sources) {
+ if (source == "") {
+ invalidLicenses.push("Invalid license: empty string in " + JSON.stringify(licenseInfo))
+ }
+ try {
+ new URL(source);
+ } catch {
+ invalidLicenses.push("Not a valid URL: " + source)
+ }
}
}
-}
-
-if (missingLicenses.length > 0) {
- const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.`
- console.log(missingLicenses.concat(invalidLicenses).join("\n"))
- console.error(msg)
- if (process.argv.indexOf("--no-fail") < 0) {
- throw msg
+
+ if (missingLicenses.length > 0) {
+ const msg = `There are ${missingLicenses.length} licenses missing and ${invalidLicenses.length} invalid licenses.`
+ console.log(missingLicenses.concat(invalidLicenses).join("\n"))
+ console.error(msg)
+ if (args.indexOf("--no-fail") < 0) {
+ throw msg
+ }
}
+
+ cleanLicenseInfo(licensePaths, licenseInfos)
+ createFullLicenseOverview(licensePaths)
}
-cleanLicenseInfo(licensePaths, licenseInfos)
-createFullLicenseOverview(licensePaths)
\ No newline at end of file
+main(process.argv.slice(2))
diff --git a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
index 2a06069ca0..c13d8d5825 100644
--- a/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
+++ b/test/Models/ThemeConfig/Conversion/PrepareTheme.spec.ts
@@ -11,6 +11,7 @@ import {ExtractImages} from "../../../../Models/ThemeConfig/Conversion/FixImages
import * as cyclofix from "../../../../assets/generated/themes/cyclofix.json"
import {Tag} from "../../../../Logic/Tags/Tag";
import {DesugaringContext} from "../../../../Models/ThemeConfig/Conversion/Conversion";
+import {And} from "../../../../Logic/Tags/And";
const themeConfigJson: LayoutConfigJson = {
@@ -52,7 +53,7 @@ describe("PrepareTheme", () => {
let themeConfigJsonPrepared = prepareStep.convert(theme, "test").result
const themeConfig = new LayoutConfig(themeConfigJsonPrepared);
const layerUnderTest = themeConfig.layers.find(l => l.id === "public_bookcase")
- expect(layerUnderTest.source.osmTags).deep.eq(new Tag("amenity","public_bookcase"))
+ expect(layerUnderTest.source.osmTags).deep.eq(new And([new Tag("amenity","public_bookcase")]))
})
diff --git a/test/UI/ValidatedTextFieldTranslations.ts b/test/UI/ValidatedTextFieldTranslations.ts
index f9082ce2eb..48234d2cd6 100644
--- a/test/UI/ValidatedTextFieldTranslations.ts
+++ b/test/UI/ValidatedTextFieldTranslations.ts
@@ -1,14 +1,17 @@
import {describe} from 'mocha'
-import {expect} from 'chai'
-import Translations from "../../UI/i18n/Translations";
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
+import {fail} from "assert";
+import Translations from "../../UI/i18n/Translations";
describe("ValidatedTextFields", () => {
-
- it("should all have description in the translations", () => {
- const ts = Translations.t.validation;
- const missingTranslations = Array.from(ValidatedTextField.allTypes.keys())
- .filter(key => ts[key] === undefined || ts[key].description === undefined)
- expect(missingTranslations, "These validated text fields don't have a type name defined in en.json. (Did you just add one? Run `npm run generate:translations`)").to.be.empty
- })
+
+ it("should all have description in the translations", () => {
+ const ts = Translations.t.validation;
+ const missingTranslations = Array.from(ValidatedTextField.allTypes.keys())
+ .filter(key => ts[key] === undefined || ts[key].description === undefined)
+ .filter(key => key !== "distance")
+ if (missingTranslations.length > 0) {
+ fail("The validated text fields don't have a description defined in en.json for "+missingTranslations.join(", ")+". (Did you just add one? Run `npm run generate:translations`)")
+ }
+ })
})