forked from MapComplete/MapComplete
		
	Move 'defaultInputUnit' into Unit, away from denomination
This commit is contained in:
		
							parent
							
								
									03057b2eff
								
							
						
					
					
						commit
						67b5a33f0b
					
				
					 9 changed files with 135 additions and 84 deletions
				
			
		|  | @ -15,7 +15,7 @@ export class Denomination { | |||
|     private readonly _human: Translation | ||||
|     private readonly _humanSingular?: Translation | ||||
| 
 | ||||
|     constructor(json: DenominationConfigJson, context: string) { | ||||
|     constructor(json: DenominationConfigJson, useAsDefaultInput: boolean, context: string) { | ||||
|         context = `${context}.unit(${json.canonicalDenomination})` | ||||
|         this.canonical = json.canonicalDenomination.trim() | ||||
|         if (this.canonical === undefined) { | ||||
|  | @ -35,7 +35,7 @@ export class Denomination { | |||
|             throw `${context} uses the old 'default'-key. Use "useIfNoUnitGiven" or "useAsDefaultInput" instead` | ||||
|         } | ||||
|         this.useIfNoUnitGiven = json.useIfNoUnitGiven | ||||
|         this.useAsDefaultInput = json.useAsDefaultInput ?? json.useIfNoUnitGiven | ||||
|         this.useAsDefaultInput = useAsDefaultInput ?? json.useIfNoUnitGiven | ||||
| 
 | ||||
|         this._human = Translations.T(json.human, context + "human") | ||||
|         this._humanSingular = Translations.T(json.humanSingular, context + "humanSingular") | ||||
|  | @ -69,7 +69,7 @@ export class Denomination { | |||
|      *               human: { | ||||
|      *                   en: "meter" | ||||
|      *               } | ||||
|      *           }, "test") | ||||
|      *           }, false, "test") | ||||
|      * unit.canonicalValue("42m", true) // =>"42 m"
 | ||||
|      * unit.canonicalValue("42", true) // =>"42 m"
 | ||||
|      * unit.canonicalValue("42 m", true) // =>"42 m"
 | ||||
|  | @ -84,7 +84,7 @@ export class Denomination { | |||
|      *               human: { | ||||
|      *                   en: "meter" | ||||
|      *               } | ||||
|      *           }, "test") | ||||
|      *           }, false, "test") | ||||
|      * unit.canonicalValue("42m", true) // =>"42"
 | ||||
|      * unit.canonicalValue("42", true) // =>"42"
 | ||||
|      * unit.canonicalValue("42 m", true) // =>"42"
 | ||||
|  |  | |||
|  | @ -389,62 +389,7 @@ export interface LayerConfigJson { | |||
|     allowSplit?: boolean | ||||
| 
 | ||||
|     /** | ||||
|      * In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...) | ||||
|      * | ||||
|      * Sometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...) | ||||
|      * | ||||
|      * This brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...) | ||||
|      * | ||||
|      * Not only do we want to write consistent data to OSM, we also want to present this consistently to the user. | ||||
|      * This is handled by defining units. | ||||
|      * | ||||
|      * # Rendering | ||||
|      * | ||||
|      * To render a value with long (human) denomination, use {canonical(key)} | ||||
|      * | ||||
|      * # Usage | ||||
|      * | ||||
|      * First of all, you define which keys have units applied, for example: | ||||
|      * | ||||
|      * ``` | ||||
|      * units: [ | ||||
|      *  appliesTo: ["maxspeed", "maxspeed:hgv", "maxspeed:bus"] | ||||
|      *  applicableUnits: [ | ||||
|      *      ... | ||||
|      *  ] | ||||
|      * ] | ||||
|      * ``` | ||||
|      * | ||||
|      * ApplicableUnits defines which is the canonical extension, how it is presented to the user, ...: | ||||
|      * | ||||
|      * ``` | ||||
|      * applicableUnits: [ | ||||
|      * { | ||||
|      *     canonicalDenomination: "km/h", | ||||
|      *     alternativeDenomination: ["km/u", "kmh", "kph"] | ||||
|      *     default: true, | ||||
|      *     human: { | ||||
|      *         en: "kilometer/hour", | ||||
|      *         nl: "kilometer/uur" | ||||
|      *     }, | ||||
|      *     humanShort: { | ||||
|      *         en: "km/h", | ||||
|      *         nl: "km/u" | ||||
|      *     } | ||||
|      * }, | ||||
|      * { | ||||
|      *     canoncialDenomination: "mph", | ||||
|      *     ... similar for miles an hour ... | ||||
|      * } | ||||
|      * ] | ||||
|      * ``` | ||||
|      * | ||||
|      * | ||||
|      * If this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage: | ||||
|      * every value will be parsed and the canonical extension will be added add presented to the other parts of the code. | ||||
|      * | ||||
|      * Also, if a freeform text field is used, an extra dropdown with applicable denominations will be given | ||||
|      * | ||||
|      * @see UnitConfigJson | ||||
|      */ | ||||
|     units?: UnitConfigJson[] | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,61 @@ | |||
| /** | ||||
|  * In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...) | ||||
|  * | ||||
|  * Sometimes, multiple denominations are possible (e.g. km/h vs mile/h; megawatt vs kilowatt vs gigawatt for power generators, ...) | ||||
|  * | ||||
|  * This brings in some troubles, as there are multiple ways to write it (no denomitation, 'm' vs 'meter' 'metre', ...) | ||||
|  * | ||||
|  * Not only do we want to write consistent data to OSM, we also want to present this consistently to the user. | ||||
|  * This is handled by defining units. | ||||
|  * | ||||
|  * # Rendering | ||||
|  * | ||||
|  * To render a value with long (human) denomination, use {canonical(key)} | ||||
|  * | ||||
|  * # Usage | ||||
|  * | ||||
|  * First of all, you define which keys have units applied, for example: | ||||
|  * | ||||
|  * ``` | ||||
|  * units: [ | ||||
|  *  appliesTo: ["maxspeed", "maxspeed:hgv", "maxspeed:bus"] | ||||
|  *  applicableUnits: [ | ||||
|  *      ... | ||||
|  *  ] | ||||
|  * ] | ||||
|  * ``` | ||||
|  * | ||||
|  * ApplicableUnits defines which is the canonical extension, how it is presented to the user, ...: | ||||
|  * | ||||
|  * ``` | ||||
|  * applicableUnits: [ | ||||
|  * { | ||||
|  *     canonicalDenomination: "km/h", | ||||
|  *     alternativeDenomination: ["km/u", "kmh", "kph"] | ||||
|  *     default: true, | ||||
|  *     human: { | ||||
|  *         en: "kilometer/hour", | ||||
|  *         nl: "kilometer/uur" | ||||
|  *     }, | ||||
|  *     humanShort: { | ||||
|  *         en: "km/h", | ||||
|  *         nl: "km/u" | ||||
|  *     } | ||||
|  * }, | ||||
|  * { | ||||
|  *     canoncialDenomination: "mph", | ||||
|  *     ... similar for miles an hour ... | ||||
|  * } | ||||
|  * ] | ||||
|  * ``` | ||||
|  * | ||||
|  * | ||||
|  * If this is defined, then every key which the denominations apply to (`maxspeed`, `maxspeed:hgv` and `maxspeed:bus`) will be rewritten at the metatagging stage: | ||||
|  * every value will be parsed and the canonical extension will be added add presented to the other parts of the code. | ||||
|  * | ||||
|  * Also, if a freeform text field is used, an extra dropdown with applicable denominations will be given | ||||
|  * | ||||
|  */ | ||||
| export default interface UnitConfigJson { | ||||
|     /** | ||||
|      * Every key from this list will be normalized. | ||||
|  | @ -11,9 +69,19 @@ export default interface UnitConfigJson { | |||
|      */ | ||||
|     eraseInvalidValues?: boolean | ||||
|     /** | ||||
|      * The possible denominations | ||||
|      * The possible denominations for this unit. | ||||
|      * For length, denominations could be "meter", "kilometer", "miles", "foot" | ||||
|      */ | ||||
|     applicableUnits: DenominationConfigJson[] | ||||
| 
 | ||||
|     /** | ||||
|      * In some cases, the default denomination is not the most user friendly to input. | ||||
|      * E.g., when measuring kerb heights, it is illogical to ask contributors to input an amount in meters. | ||||
|      * | ||||
|      * When a default input method should be used, this can be specified by setting the canonical denomination here, e.g. | ||||
|      * `defaultInput: "cm"`. This must be a denomination which appears in the applicableUnits | ||||
|      */ | ||||
|     defaultInput?: string | ||||
| } | ||||
| 
 | ||||
| export interface DenominationConfigJson { | ||||
|  | @ -28,12 +96,6 @@ export interface DenominationConfigJson { | |||
|      */ | ||||
|     useIfNoUnitGiven?: boolean | string[] | ||||
| 
 | ||||
|     /** | ||||
|      * Use this value as default denomination when the user inputs a value (e.g. to force using 'centimeters' instead of 'meters' by default). | ||||
|      * If unset for all values, this will use 'useIfNoUnitGiven'. If at least one denomination has this set, this will default to false | ||||
|      */ | ||||
|     useAsDefaultInput?: boolean | string[] | ||||
| 
 | ||||
|     /** | ||||
|      * The canonical value for this denomination which will be added to the value in OSM. | ||||
|      * e.g. "m" for meters | ||||
|  | @ -46,12 +108,15 @@ export interface DenominationConfigJson { | |||
| 
 | ||||
|     /** | ||||
|      * The canonical denomination in the case that the unit is precisely '1'. | ||||
|      * Used for display purposes | ||||
|      * Used for display purposes only. | ||||
|      * | ||||
|      * E.g.: for duration of something in minutes: `2 minutes` but `1 minute`; the `minute` goes here | ||||
|      */ | ||||
|     canonicalDenominationSingular?: string | ||||
| 
 | ||||
|     /** | ||||
|      * A list of alternative values which can occur in the OSM database - used for parsing. | ||||
|      * E.g.: while 'm' is canonical, `meter`, `mtrs`, ... can occur as well | ||||
|      */ | ||||
|     alternativeDenomination?: string[] | ||||
| 
 | ||||
|  | @ -62,16 +127,16 @@ export interface DenominationConfigJson { | |||
|      *     "fr": "metre" | ||||
|      * } | ||||
|      */ | ||||
|     human?: string | any | ||||
|     human?: string | Record<string, string> | ||||
| 
 | ||||
|     /** | ||||
|      * The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g. | ||||
|      * { | ||||
|      *     "en": "minute", | ||||
|      *     "nl": "minuut"x² | ||||
|      *     "nl": "minuut" | ||||
|      * } | ||||
|      */ | ||||
|     humanSingular?: string | any | ||||
|     humanSingular?: string | Record<string, string> | ||||
| 
 | ||||
|     /** | ||||
|      * If set, then the canonical value will be prefixed instead, e.g. for '€' | ||||
|  |  | |||
|  | @ -60,6 +60,44 @@ export class Unit { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * | ||||
|      * // Should detect invalid defaultInput
 | ||||
|      * let threwError = false | ||||
|      * try{ | ||||
|      *   Unit.fromJson({ | ||||
|      *     appliesToKey: ["length"], | ||||
|      *     defaultInput: "xcm", | ||||
|      *     applicableUnits: [ | ||||
|      *         { | ||||
|      *             canonicalDenomination: "m", | ||||
|      *             useIfNoUnitGiven: true, | ||||
|      *             human: "meter" | ||||
|      *         } | ||||
|      *     ] | ||||
|      *   },"test") | ||||
|      * }catch(e){ | ||||
|      *     threwError =true | ||||
|      * } | ||||
|      * threwError // => false
 | ||||
|      * | ||||
|      * // Should work
 | ||||
|      * Unit.fromJson({ | ||||
|      *     appliesToKey: ["length"], | ||||
|      *     defaultInput: "xcm", | ||||
|      *     applicableUnits: [ | ||||
|      *         { | ||||
|      *             canonicalDenomination: "m", | ||||
|      *             useIfNoUnitGiven: true, | ||||
|      *             humen: "meter" | ||||
|      *         }, | ||||
|      *         { | ||||
|      *             canonicalDenomination: "cm", | ||||
|      *             human: "centimeter" | ||||
|      *         } | ||||
|      *     ] | ||||
|      * }, "test") | ||||
|      */ | ||||
|     static fromJson(json: UnitConfigJson, ctx: string) { | ||||
|         const appliesTo = json.appliesToKey | ||||
|         for (let i = 0; i < appliesTo.length; i++) { | ||||
|  | @ -74,14 +112,13 @@ export class Unit { | |||
|         } | ||||
|         // Some keys do have unit handling
 | ||||
| 
 | ||||
|         if (json.applicableUnits.some((denom) => denom.useAsDefaultInput !== undefined)) { | ||||
|             json.applicableUnits.forEach((denom) => { | ||||
|                 denom.useAsDefaultInput = denom.useAsDefaultInput ?? false | ||||
|             }) | ||||
|         } | ||||
| 
 | ||||
|         const applicable = json.applicableUnits.map( | ||||
|             (u, i) => new Denomination(u, `${ctx}.units[${i}]`) | ||||
|             (u, i) => | ||||
|                 new Denomination( | ||||
|                     u, | ||||
|                     u.canonicalDenomination.trim() === json.defaultInput, | ||||
|                     `${ctx}.units[${i}]` | ||||
|                 ) | ||||
|         ) | ||||
|         return new Unit(appliesTo, applicable, json.eraseInvalidValues ?? false) | ||||
|     } | ||||
|  |  | |||
|  | @ -205,6 +205,7 @@ | |||
|         "elevator:width", | ||||
|         "elevator:depth" | ||||
|       ], | ||||
|       "defaultInput": "cm", | ||||
|       "applicableUnits": [ | ||||
|         { | ||||
|           "canonicalDenomination": "m", | ||||
|  | @ -221,7 +222,6 @@ | |||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "useAsDefaultInput": true, | ||||
|           "canonicalDenomination": "cm", | ||||
|           "alternativeDenomination": [ | ||||
|             "centimeter", | ||||
|  |  | |||
|  | @ -473,6 +473,7 @@ | |||
|         "kerb:height", | ||||
|         "width" | ||||
|       ], | ||||
|       "defaultInput": "cm", | ||||
|       "applicableUnits": [ | ||||
|         { | ||||
|           "useIfNoUnitGiven": true, | ||||
|  | @ -489,7 +490,6 @@ | |||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "useAsDefaultInput": true, | ||||
|           "canonicalDenomination": "cm", | ||||
|           "alternativeDenomination": [ | ||||
|             "centimeter", | ||||
|  |  | |||
							
								
								
									
										3
									
								
								assets/layers/units/units.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								assets/layers/units/units.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| { | ||||
| 
 | ||||
| } | ||||
|  | @ -63,6 +63,7 @@ | |||
|         "width", | ||||
|         "_biggest_width" | ||||
|       ], | ||||
|       "defaultUnit": "cm", | ||||
|       "applicableUnits": [ | ||||
|         { | ||||
|           "useIfNoUnitGiven": true, | ||||
|  | @ -79,7 +80,6 @@ | |||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "useAsDefaultInput": true, | ||||
|           "canonicalDenomination": "cm", | ||||
|           "alternativeDenomination": [ | ||||
|             "centimeter", | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ describe("Unit", () => { | |||
|                     nl: " megawatt", | ||||
|                 }, | ||||
|             }, | ||||
|             false, | ||||
|             "test" | ||||
|         ) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue