forked from MapComplete/MapComplete
		
	Add more docs, add more checks, add more tests
This commit is contained in:
		
							parent
							
								
									a50b9fba59
								
							
						
					
					
						commit
						2c3c110624
					
				
					 7 changed files with 162 additions and 13 deletions
				
			
		|  | @ -82,8 +82,11 @@ export default class TagRenderingConfig { | |||
| 
 | ||||
|         this.multiAnswer = json.multiAnswer ?? false | ||||
|         if (json.mappings) { | ||||
|              | ||||
|              | ||||
|             this.mappings = json.mappings.map((mapping, i) => { | ||||
| 
 | ||||
| 
 | ||||
|                 if (mapping.then === undefined) { | ||||
|                     throw `${context}.mapping[${i}]: Invalid mapping: if without body` | ||||
|                 } | ||||
|  | @ -104,7 +107,7 @@ export default class TagRenderingConfig { | |||
|                     hideInAnswer: hideInAnswer | ||||
|                 }; | ||||
|                 if (this.question) { | ||||
|                     if (hideInAnswer !== true && !mp.if.isUsableAsAnswer()) { | ||||
|                     if (hideInAnswer !== true && mp.if !== undefined && !mp.if.isUsableAsAnswer()) { | ||||
|                         throw `${context}.mapping[${i}].if: This value cannot be used to answer a question, probably because it contains a regex or an OR. Either change it or set 'hideInAnswer'` | ||||
|                     } | ||||
| 
 | ||||
|  | @ -128,6 +131,32 @@ export default class TagRenderingConfig { | |||
|         if(this.render && this.question && this.freeform === undefined){ | ||||
|             throw `${context}: Detected a tagrendering which takes input without freeform key in ${context}` | ||||
|         } | ||||
|          | ||||
|         if(!json.multiAnswer && this.mappings !== undefined && this.question !== undefined){ | ||||
|             let keys = [] | ||||
|             for (let i = 0; i < this.mappings.length; i++){ | ||||
|                 const mapping = this.mappings[i]; | ||||
|                 if(mapping.if === undefined){ | ||||
|                     throw `${context}.mappings[${i}].if is undefined` | ||||
|                 } | ||||
|                 keys.push(...mapping.if.usedKeys()) | ||||
|             } | ||||
|             keys = Utils.Dedup(keys) | ||||
|             for (let i = 0; i < this.mappings.length; i++){ | ||||
|                 const mapping = this.mappings[i]; | ||||
|                 if(mapping.hideInAnswer){ | ||||
|                     continue | ||||
|                 } | ||||
|                  | ||||
|                 const usedKeys = mapping.if.usedKeys(); | ||||
|                 for (const expectedKey of keys) { | ||||
|                     if(usedKeys.indexOf(expectedKey) < 0){ | ||||
|                         const msg = `${context}.mappings[${i}]: This mapping only defines values for ${usedKeys.join(', ')}, but it should also give a value for ${expectedKey}` | ||||
|                         console.warn(msg) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (this.question !== undefined && json.multiAnswer) { | ||||
|             if ((this.mappings?.length ?? 0) === 0) { | ||||
|  |  | |||
|  | @ -49,14 +49,64 @@ export interface TagRenderingConfigJson { | |||
|      * Allows fixed-tag inputs, shown either as radiobuttons or as checkboxes | ||||
|      */ | ||||
|     mappings?: { | ||||
|         /** | ||||
|          * If this condition is met, then the text under `then` will be shown. | ||||
|          * If no value matches, and the user selects this mapping as an option, then these tags will be uploaded to OSM. | ||||
|          */ | ||||
|         if: AndOrTagConfigJson | string, | ||||
|         /** | ||||
|          * Only applicable if 'multiAnswer' is set. | ||||
|          * This tag is applied if the respective checkbox is unset | ||||
|          * If the condition `if` is met, the text `then` will be rendered. | ||||
|          * If not known yet, the user will be presented with `then` as an option | ||||
|          */ | ||||
|         ifnot?: AndOrTagConfigJson | string, | ||||
|         then: string | any | ||||
|         hideInAnswer?: boolean | ||||
|         then: string | any, | ||||
|         /** | ||||
|          * In some cases, multiple taggings exist (e.g. a default assumption, or a commonly mapped abbreviation and a fully written variation). | ||||
|          *  | ||||
|          * In the latter case, a correct text should be shown, but only a single, canonical tagging should be selectable by the user. | ||||
|          * In this case, one of the mappings can be hiden by setting this flag. | ||||
|          *  | ||||
|          * To demonstrate an example making a default assumption: | ||||
|          *  | ||||
|          * mappings: [ | ||||
|          *  { | ||||
|          *      if: "access=", -- no access tag present, we assume accessible | ||||
|          *      then: "Accessible to the general public", | ||||
|          *      hideInAnswer: true | ||||
|          *  }, | ||||
|          *  { | ||||
|          *      if: "access=yes", | ||||
|          *      then: "Accessible to the general public", -- the user selected this, we add that to OSM | ||||
|          *  }, | ||||
|          *  { | ||||
|          *      if: "access=no", | ||||
|          *      then: "Not accessible to the public" | ||||
|          *  } | ||||
|          * ] | ||||
|          *  | ||||
|          *  | ||||
|          * For example, for an operator, we have `operator=Agentschap Natuur en Bos`, which is often abbreviated to `operator=ANB`. | ||||
|          * Then, we would add two mappings: | ||||
|          * { | ||||
|          *     if: "operator=Agentschap Natuur en Bos" -- the non-abbreviated version which should be uploaded | ||||
|          *     then: "Maintained by Agentschap Natuur en Bos" | ||||
|          * }, | ||||
|          * { | ||||
|          *     if: "operator=ANB", -- we don't want to upload abbreviations | ||||
|          *     then: "Maintained by Agentschap Natuur en Bos" | ||||
|          *     hideInAnswer: true | ||||
|          * } | ||||
|          */ | ||||
|         hideInAnswer?: boolean, | ||||
|         /** | ||||
|          * Only applicable if 'multiAnswer' is set. | ||||
|          * This is for situations such as: | ||||
|          * `accepts:coins=no` where one can select all the possible payment methods. However, we want to make explicit that some options _were not_ selected. | ||||
|          * This can be done with `ifnot` | ||||
|          * Note that we can not explicitly render this negative case to the user, we cannot show `does _not_ accept coins`. | ||||
|          * If this is important to your usecase, consider using multiple radiobutton-fields without `multiAnswer` | ||||
|          */ | ||||
|         ifnot?: AndOrTagConfigJson | string | ||||
|          | ||||
|     }[] | ||||
| 
 | ||||
|     /** | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue