forked from MapComplete/MapComplete
		
	Only do ID-check on tagrenderings for official themes
This commit is contained in:
		
							parent
							
								
									746273f594
								
							
						
					
					
						commit
						0018fcf1f0
					
				
					 17 changed files with 150 additions and 123 deletions
				
			
		|  | @ -2,7 +2,7 @@ import {Utils} from "../Utils"; | |||
| 
 | ||||
| export default class Constants { | ||||
| 
 | ||||
|     public static vNumber = "0.12.6"; | ||||
|     public static vNumber = "0.12.7"; | ||||
|     public static ImgurApiKey = '7070e7167f0a25a' | ||||
|     public static readonly mapillary_client_token_v3 = 'TXhLaWthQ1d4RUg0czVxaTVoRjFJZzowNDczNjUzNmIyNTQyYzI2' | ||||
|     public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85" | ||||
|  |  | |||
|  | @ -133,7 +133,6 @@ export default class LayerConfig extends WithContextLoader { | |||
|                 const code = kv.substring(index + 1); | ||||
| 
 | ||||
|                 try { | ||||
| 
 | ||||
|                     new Function("feat", "return " + code + ";"); | ||||
|                 } catch (e) { | ||||
|                     throw `Invalid function definition: code ${code} is invalid:${e} (at ${context})` | ||||
|  | @ -225,9 +224,8 @@ export default class LayerConfig extends WithContextLoader { | |||
|             throw "Missing ids in tagrenderings" | ||||
|         } | ||||
| 
 | ||||
|         this.tagRenderings = this.ExtractLayerTagRenderings(json) | ||||
|         { | ||||
| 
 | ||||
|         this.tagRenderings = this.ExtractLayerTagRenderings(json, official) | ||||
|         if (official) { | ||||
| 
 | ||||
|             const emptyIds = this.tagRenderings.filter(tr => tr.id === ""); | ||||
|             if (emptyIds.length > 0) { | ||||
|  | @ -265,7 +263,9 @@ export default class LayerConfig extends WithContextLoader { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         this.titleIcons = this.ParseTagRenderings(titleIcons, true); | ||||
|         this.titleIcons = this.ParseTagRenderings(titleIcons, { | ||||
|             readOnlyMode: true | ||||
|         }); | ||||
| 
 | ||||
|         this.title = this.tr("title", undefined); | ||||
|         this.isShown = this.tr("isShown", "yes"); | ||||
|  | @ -309,7 +309,7 @@ export default class LayerConfig extends WithContextLoader { | |||
|         return mapRendering.GenerateLeafletStyle(defaultTags, false, {noSize: true}).html | ||||
|     } | ||||
| 
 | ||||
|     public ExtractLayerTagRenderings(json: LayerConfigJson): TagRenderingConfig[] { | ||||
|     public ExtractLayerTagRenderings(json: LayerConfigJson, official: boolean): TagRenderingConfig[] { | ||||
| 
 | ||||
|         if (json.tagRenderings === undefined) { | ||||
|             return [] | ||||
|  | @ -342,12 +342,16 @@ export default class LayerConfig extends WithContextLoader { | |||
|             throw `Error in ${this._context}.tagrenderings[${i}]: got a value which defines either \`rewrite\` or \`renderings\`, but not both. Either define both or move the \`renderings\`  out of this scope` | ||||
|         } | ||||
| 
 | ||||
|         const allRenderings = this.ParseTagRenderings(normalTagRenderings, false); | ||||
|         const allRenderings = this.ParseTagRenderings(normalTagRenderings, | ||||
|             { | ||||
|                 requiresId: official | ||||
|             }); | ||||
| 
 | ||||
|         if (renderingsToRewrite.length === 0) { | ||||
|             return allRenderings | ||||
|         } | ||||
| 
 | ||||
|         /* Used for left|right group creation and replacement */ | ||||
|         function prepConfig(keyToRewrite: string, target: string, tr: TagRenderingConfigJson) { | ||||
| 
 | ||||
|             function replaceRecursive(transl: string | any) { | ||||
|  | @ -379,7 +383,9 @@ export default class LayerConfig extends WithContextLoader { | |||
|             const textToReplace = rewriteGroup.rewrite.sourceString | ||||
|             const targets = rewriteGroup.rewrite.into | ||||
|             for (const target of targets) { | ||||
|                 const parsedRenderings = this.ParseTagRenderings(tagRenderings, false, tr => prepConfig(textToReplace, target, tr)) | ||||
|                 const parsedRenderings = this.ParseTagRenderings(tagRenderings,  { | ||||
|                     prepConfig: tr => prepConfig(textToReplace, target, tr) | ||||
|                 }) | ||||
| 
 | ||||
|                 if (!rewriteGroups.has(target)) { | ||||
|                     rewriteGroups.set(target, []) | ||||
|  |  | |||
|  | @ -71,6 +71,10 @@ export default class TagRenderingConfig { | |||
| 
 | ||||
| 
 | ||||
|         this.id = json.id ?? ""; | ||||
|         if(this.id.match(/^[a-zA-Z0-9 ()?\/=:;,_-]*$/) === null){ | ||||
|             throw "Invalid ID in "+context+": an id can only contain [a-zA-Z0-0_-] as characters. The offending id is: "+this.id | ||||
|         } | ||||
|          | ||||
|         this.group = json.group ?? ""; | ||||
|         this.render = Translations.T(json.render, context + ".render"); | ||||
|         this.question = Translations.T(json.question, context + ".question"); | ||||
|  | @ -173,6 +177,18 @@ export default class TagRenderingConfig { | |||
|             throw `${context}: A question is defined, but no mappings nor freeform (key) are. The question is ${this.question.txt} at ${context}` | ||||
|         } | ||||
| 
 | ||||
|         if (this.id === "questions" && this.render !== undefined) { | ||||
|             for (const ln in this.render.translations) { | ||||
|                 const txt :string = this.render.translations[ln] | ||||
|                 if(txt.indexOf("{questions}") >= 0){ | ||||
|                     continue | ||||
|                 } | ||||
|                 throw `${context}: The rendering for language ${ln} does not contain {questions}. This is a bug, as this rendering should include exactly this to trigger those questions to be shown!` | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         if (this.freeform) { | ||||
|             if(this.render === undefined){ | ||||
|                 throw `${context}: Detected a freeform key without rendering... Key: ${this.freeform.key} in ${context}` | ||||
|  | @ -202,16 +218,6 @@ export default class TagRenderingConfig { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (this.id === "questions" && this.render !== undefined) { | ||||
|             for (const ln in this.render.translations) { | ||||
|                 const txt :string = this.render.translations[ln] | ||||
|                 if(txt.indexOf("{questions}") >= 0){ | ||||
|                     continue | ||||
|                 } | ||||
|                 throw `${context}: The rendering for language ${ln} does not contain {questions}. This is a bug, as this rendering should include exactly this to trigger those questions to be shown!` | ||||
| 
 | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         if (this.render && this.question && this.freeform === undefined) { | ||||
|  |  | |||
|  | @ -48,9 +48,16 @@ export default class WithContextLoader { | |||
|      * A string is interpreted as a name to call | ||||
|      */ | ||||
|     public ParseTagRenderings( | ||||
|         tagRenderings?: (string | { builtin: string, override: any } | TagRenderingConfigJson)[], | ||||
|         readOnly = false, | ||||
|         prepConfig: ((config: TagRenderingConfigJson) => TagRenderingConfigJson) = undefined | ||||
|         tagRenderings: (string | { builtin: string, override: any } | TagRenderingConfigJson)[], | ||||
|         options?:{ | ||||
|             /** | ||||
|              * Throw an error if 'question' is defined | ||||
|              */ | ||||
|             readOnlyMode?: boolean, | ||||
|             requiresId?: boolean | ||||
|             prepConfig?: ((config: TagRenderingConfigJson) => TagRenderingConfigJson) | ||||
|              | ||||
|         } | ||||
|     ): TagRenderingConfig[] { | ||||
|         if (tagRenderings === undefined) { | ||||
|             return []; | ||||
|  | @ -58,8 +65,9 @@ export default class WithContextLoader { | |||
| 
 | ||||
|         const context = this._context | ||||
|         const renderings: TagRenderingConfig[] = [] | ||||
|         if (prepConfig === undefined) { | ||||
|             prepConfig = c => c | ||||
|         options = options ?? {} | ||||
|         if (options.prepConfig === undefined) { | ||||
|             options.prepConfig = c => c | ||||
|         } | ||||
|         for (let i = 0; i < tagRenderings.length; i++) { | ||||
|             let renderingJson = tagRenderings[i] | ||||
|  | @ -89,9 +97,16 @@ export default class WithContextLoader { | |||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             const patchedConfig = prepConfig(<TagRenderingConfigJson>renderingJson) | ||||
|             const patchedConfig = options.prepConfig(<TagRenderingConfigJson>renderingJson) | ||||
| 
 | ||||
|             const tr = new TagRenderingConfig(patchedConfig, `${context}.tagrendering[${i}]`); | ||||
|             if(options.readOnlyMode && tr.question !== undefined){ | ||||
|                 throw "A question is defined for "+`${context}.tagrendering[${i}], but this is not allowed at this position - probably because this rendering is an icon, badge or label` | ||||
|             } | ||||
|             if(options.requiresId && tr.id === ""){ | ||||
|                 throw `${context}.tagrendering[${i}] has an invalid ID - make sure it is defined and not empty` | ||||
|             } | ||||
|              | ||||
|             renderings.push(tr) | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -368,7 +368,7 @@ | |||
|       "freeform": { | ||||
|         "key": "description" | ||||
|       }, | ||||
|       "id": "Non-editable description {description}" | ||||
|       "id": "Non-editable description" | ||||
|     }, | ||||
|     { | ||||
|       "question": "Is er extra info die je kwijt wil?", | ||||
|  | @ -378,7 +378,7 @@ | |||
|       "freeform": { | ||||
|         "key": "description:0" | ||||
|       }, | ||||
|       "id": "Editable description {description:0}" | ||||
|       "id": "Editable description" | ||||
|     }, | ||||
|     { | ||||
|       "render": { | ||||
|  |  | |||
|  | @ -140,7 +140,7 @@ | |||
|           "hideInAnswer": true | ||||
|         } | ||||
|       ], | ||||
|       "id": "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view" | ||||
|       "id": "camera_direction" | ||||
|     }, | ||||
|     { | ||||
|       "freeform": { | ||||
|  | @ -264,7 +264,7 @@ | |||
|           "hideInAnswer": true | ||||
|         } | ||||
|       ], | ||||
|       "id": "Indoor camera? This isn't clear for 'public'-cameras" | ||||
|       "id": "is_indoor" | ||||
|     }, | ||||
|     { | ||||
|       "question": { | ||||
|  |  | |||
|  | @ -558,7 +558,7 @@ | |||
|         } | ||||
|       }, | ||||
|       { | ||||
|         "id": "Non-editable description {description}", | ||||
|         "id": "Non-editable description", | ||||
|         "render": { | ||||
|           "nl": "Extra info: <i>{description}</i>" | ||||
|         }, | ||||
|  | @ -567,7 +567,7 @@ | |||
|         } | ||||
|       }, | ||||
|       { | ||||
|         "id": "Editable description {description:0}", | ||||
|         "id": "Editable description", | ||||
|         "question": "Is er extra info die je kwijt wil?<br/><span class='subtle'>De <i>naam</i> van het gebied wordt in de volgende vraag gesteld</span>", | ||||
|         "render": { | ||||
|           "nl": "Extra info via buurtnatuur.be: <i>{description:0}</i>" | ||||
|  |  | |||
|  | @ -713,7 +713,7 @@ | |||
|             "it": "<h3>Contiene {_contained_climbing_routes_count} vie</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "condition": "_contained_climbing_routes~*", | ||||
|           "id": "Containe {_contained_climbing_routes_count} routes" | ||||
|           "id": "Contained_climbing_routes" | ||||
|         }, | ||||
|         { | ||||
|           "render": { | ||||
|  |  | |||
|  | @ -2397,20 +2397,6 @@ | |||
|         }, | ||||
|         "question": "Um welche Kameratyp handelt se sich?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Diese Kamera befindet sich im Innenraum" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Diese Kamera befindet sich im Freien" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Diese Kamera ist möglicherweise im Freien" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Handelt es sich bei dem von dieser Kamera überwachten öffentlichen Raum um einen Innen- oder Außenbereich?" | ||||
|       }, | ||||
|       "Level": { | ||||
|         "question": "Auf welcher Ebene befindet sich diese Kamera?", | ||||
|         "render": "Befindet sich auf Ebene {level}" | ||||
|  | @ -2472,8 +2458,22 @@ | |||
|         "question": "Wie ist diese Kamera montiert?", | ||||
|         "render": "Montageart: {camera:mount}" | ||||
|       }, | ||||
|       "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view": { | ||||
|       "camera_direction": { | ||||
|         "question": "In welche Himmelsrichtung ist diese Kamera ausgerichtet?" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Diese Kamera befindet sich im Innenraum" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Diese Kamera befindet sich im Freien" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Diese Kamera ist möglicherweise im Freien" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Handelt es sich bei dem von dieser Kamera überwachten öffentlichen Raum um einen Innen- oder Außenbereich?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -3656,20 +3656,6 @@ | |||
|         }, | ||||
|         "question": "What kind of camera is this?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "This camera is located indoors" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "This camera is located outdoors" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "This camera is probably located outdoors" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Is the public space surveilled by this camera an indoor or outdoor space?" | ||||
|       }, | ||||
|       "Level": { | ||||
|         "question": "On which level is this camera located?", | ||||
|         "render": "Located on level {level}" | ||||
|  | @ -3731,7 +3717,7 @@ | |||
|         "question": "How is this camera placed?", | ||||
|         "render": "Mounting method: {camera:mount}" | ||||
|       }, | ||||
|       "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view": { | ||||
|       "camera_direction": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Films to a compass heading of {direction}" | ||||
|  | @ -3739,6 +3725,20 @@ | |||
|         }, | ||||
|         "question": "In which geographical direction does this camera film?", | ||||
|         "render": "Films to a compass heading of {camera:direction}" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "This camera is located indoors" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "This camera is located outdoors" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "This camera is probably located outdoors" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Is the public space surveilled by this camera an indoor or outdoor space?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -1592,20 +1592,6 @@ | |||
|         }, | ||||
|         "question": "Quel genre de caméra est-ce ?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Cette caméra est située à l'intérieur" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Cette caméra est située à l'extérieur" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Cette caméra est probablement située à l'extérieur" | ||||
|           } | ||||
|         }, | ||||
|         "question": "L'espace public surveillé par cette caméra est-il un espace intérieur ou extérieur ?" | ||||
|       }, | ||||
|       "Level": { | ||||
|         "question": "À quel niveau se trouve cette caméra ?", | ||||
|         "render": "Situé au niveau {level}" | ||||
|  | @ -1667,7 +1653,7 @@ | |||
|         "question": "Comment cette caméra est-elle placée ?", | ||||
|         "render": "Méthode de montage : {camera:mount}" | ||||
|       }, | ||||
|       "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view": { | ||||
|       "camera_direction": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Filme dans une direction {direction}" | ||||
|  | @ -1675,6 +1661,20 @@ | |||
|         }, | ||||
|         "question": "Dans quelle direction géographique cette caméra filme-t-elle ?", | ||||
|         "render": "Filme dans une direction {camera:direction}" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Cette caméra est située à l'intérieur" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Cette caméra est située à l'extérieur" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Cette caméra est probablement située à l'extérieur" | ||||
|           } | ||||
|         }, | ||||
|         "question": "L'espace public surveillé par cette caméra est-il un espace intérieur ou extérieur ?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -1477,20 +1477,6 @@ | |||
|         }, | ||||
|         "question": "Di che tipo di videocamera si tratta?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Questa videocamera si trova al chiuso" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Questa videocamera si trova all'aperto" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Questa videocamera si trova probabilmente all'esterno" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Lo spazio pubblico sorvegliato da questa videocamera è all'aperto o al chiuso?" | ||||
|       }, | ||||
|       "Level": { | ||||
|         "question": "A che piano si trova questa videocamera?", | ||||
|         "render": "Si trova al piano {level}" | ||||
|  | @ -1552,7 +1538,7 @@ | |||
|         "question": "Com'è posizionata questa telecamera?", | ||||
|         "render": "Metodo di montaggio: {camera:mount}" | ||||
|       }, | ||||
|       "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view": { | ||||
|       "camera_direction": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Punta in direzione {direction}" | ||||
|  | @ -1560,6 +1546,20 @@ | |||
|         }, | ||||
|         "question": "In quale direzione geografica punta questa videocamera?", | ||||
|         "render": "Punta in direzione {camera:direction}" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Questa videocamera si trova al chiuso" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Questa videocamera si trova all'aperto" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Questa videocamera si trova probabilmente all'esterno" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Lo spazio pubblico sorvegliato da questa videocamera è all'aperto o al chiuso?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -3149,7 +3149,7 @@ | |||
|         }, | ||||
|         "question": "Zijn honden toegelaten in dit gebied?" | ||||
|       }, | ||||
|       "Editable description {description:0}": { | ||||
|       "Editable description": { | ||||
|         "render": "Extra info: <i>{description:0}</i>" | ||||
|       }, | ||||
|       "Email": { | ||||
|  | @ -3169,7 +3169,7 @@ | |||
|         "question": "Wat is de Nederlandstalige naam van dit gebied?", | ||||
|         "render": "Dit gebied heet {name:nl}" | ||||
|       }, | ||||
|       "Non-editable description {description}": { | ||||
|       "Non-editable description": { | ||||
|         "render": "Extra info: <i>{description}</i>" | ||||
|       }, | ||||
|       "Operator tag": { | ||||
|  | @ -3966,20 +3966,6 @@ | |||
|         }, | ||||
|         "question": "Wat voor soort camera is dit?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Deze camera bevindt zich binnen" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Deze camera bevindt zich buiten" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Deze camera bevindt zich waarschijnlijk buiten" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Bevindt de bewaakte publieke ruimte camera zich binnen of buiten?" | ||||
|       }, | ||||
|       "Level": { | ||||
|         "question": "Op welke verdieping bevindt deze camera zich?", | ||||
|         "render": "Bevindt zich op verdieping {level}" | ||||
|  | @ -4041,7 +4027,7 @@ | |||
|         "question": "Hoe is deze camera geplaatst?", | ||||
|         "render": "Montage: {camera:mount}" | ||||
|       }, | ||||
|       "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view": { | ||||
|       "camera_direction": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Filmt in kompasrichting {direction}" | ||||
|  | @ -4049,6 +4035,20 @@ | |||
|         }, | ||||
|         "question": "In welke geografische richting filmt deze camera?", | ||||
|         "render": "Filmt in kompasrichting {camera:direction}" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "0": { | ||||
|             "then": "Deze camera bevindt zich binnen" | ||||
|           }, | ||||
|           "1": { | ||||
|             "then": "Deze camera bevindt zich buiten" | ||||
|           }, | ||||
|           "2": { | ||||
|             "then": "Deze camera bevindt zich waarschijnlijk buiten" | ||||
|           } | ||||
|         }, | ||||
|         "question": "Bevindt de bewaakte publieke ruimte camera zich binnen of buiten?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -1219,7 +1219,10 @@ | |||
|         }, | ||||
|         "question": "Какая это камера?" | ||||
|       }, | ||||
|       "Indoor camera? This isn't clear for 'public'-cameras": { | ||||
|       "camera:mount": { | ||||
|         "question": "Как расположена эта камера?" | ||||
|       }, | ||||
|       "is_indoor": { | ||||
|         "mappings": { | ||||
|           "1": { | ||||
|             "then": "Эта камера расположена снаружи" | ||||
|  | @ -1228,9 +1231,6 @@ | |||
|             "then": "Возможно, эта камера расположена снаружи" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "camera:mount": { | ||||
|         "question": "Как расположена эта камера?" | ||||
|       } | ||||
|     }, | ||||
|     "title": { | ||||
|  |  | |||
|  | @ -370,15 +370,15 @@ | |||
|           } | ||||
|         }, | ||||
|         "tagRenderings": { | ||||
|           "Containe {_contained_climbing_routes_count} routes": { | ||||
|             "render": "<h3>Contains {_contained_climbing_routes_count} routes</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Contained routes hist": { | ||||
|             "render": "<h3>Difficulties overview</h3>{histogram(_difficulty_hist)}" | ||||
|           }, | ||||
|           "Contained routes length hist": { | ||||
|             "render": "<h3>Length overview</h3>{histogram(_length_hist)}" | ||||
|           }, | ||||
|           "Contained_climbing_routes": { | ||||
|             "render": "<h3>Contains {_contained_climbing_routes_count} routes</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Rock type (crag/rock/cliff only)": { | ||||
|             "mappings": { | ||||
|               "0": { | ||||
|  |  | |||
|  | @ -357,15 +357,15 @@ | |||
|           } | ||||
|         }, | ||||
|         "tagRenderings": { | ||||
|           "Containe {_contained_climbing_routes_count} routes": { | ||||
|             "render": "<h3>Contient {_contained_climbing_routes_count} voies</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Contained routes hist": { | ||||
|             "render": "<h3>Résumé des difficultés</h3>{histogram(_difficulty_hist)}" | ||||
|           }, | ||||
|           "Contained routes length hist": { | ||||
|             "render": "<h3>Résumé de longueur</h3>{histogram(_length_hist)}" | ||||
|           }, | ||||
|           "Contained_climbing_routes": { | ||||
|             "render": "<h3>Contient {_contained_climbing_routes_count} voies</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Rock type (crag/rock/cliff only)": { | ||||
|             "mappings": { | ||||
|               "0": { | ||||
|  |  | |||
|  | @ -370,15 +370,15 @@ | |||
|           } | ||||
|         }, | ||||
|         "tagRenderings": { | ||||
|           "Containe {_contained_climbing_routes_count} routes": { | ||||
|             "render": "<h3>Contiene {_contained_climbing_routes_count} vie</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Contained routes hist": { | ||||
|             "render": "<h3>Riassunto delle difficoltà</h3>{histogram(_difficulty_hist)}" | ||||
|           }, | ||||
|           "Contained routes length hist": { | ||||
|             "render": "<h3>Riassunto della lunghezza</h3>{histogram(_length_hist)}" | ||||
|           }, | ||||
|           "Contained_climbing_routes": { | ||||
|             "render": "<h3>Contiene {_contained_climbing_routes_count} vie</h3> <ul>{_contained_climbing_routes}</ul>" | ||||
|           }, | ||||
|           "Rock type (crag/rock/cliff only)": { | ||||
|             "mappings": { | ||||
|               "0": { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue