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 _human: Translation | ||||||
|     private readonly _humanSingular?: Translation |     private readonly _humanSingular?: Translation | ||||||
| 
 | 
 | ||||||
|     constructor(json: DenominationConfigJson, context: string) { |     constructor(json: DenominationConfigJson, useAsDefaultInput: boolean, context: string) { | ||||||
|         context = `${context}.unit(${json.canonicalDenomination})` |         context = `${context}.unit(${json.canonicalDenomination})` | ||||||
|         this.canonical = json.canonicalDenomination.trim() |         this.canonical = json.canonicalDenomination.trim() | ||||||
|         if (this.canonical === undefined) { |         if (this.canonical === undefined) { | ||||||
|  | @ -35,7 +35,7 @@ export class Denomination { | ||||||
|             throw `${context} uses the old 'default'-key. Use "useIfNoUnitGiven" or "useAsDefaultInput" instead` |             throw `${context} uses the old 'default'-key. Use "useIfNoUnitGiven" or "useAsDefaultInput" instead` | ||||||
|         } |         } | ||||||
|         this.useIfNoUnitGiven = json.useIfNoUnitGiven |         this.useIfNoUnitGiven = json.useIfNoUnitGiven | ||||||
|         this.useAsDefaultInput = json.useAsDefaultInput ?? json.useIfNoUnitGiven |         this.useAsDefaultInput = useAsDefaultInput ?? json.useIfNoUnitGiven | ||||||
| 
 | 
 | ||||||
|         this._human = Translations.T(json.human, context + "human") |         this._human = Translations.T(json.human, context + "human") | ||||||
|         this._humanSingular = Translations.T(json.humanSingular, context + "humanSingular") |         this._humanSingular = Translations.T(json.humanSingular, context + "humanSingular") | ||||||
|  | @ -69,7 +69,7 @@ export class Denomination { | ||||||
|      *               human: { |      *               human: { | ||||||
|      *                   en: "meter" |      *                   en: "meter" | ||||||
|      *               } |      *               } | ||||||
|      *           }, "test") |      *           }, false, "test") | ||||||
|      * unit.canonicalValue("42m", true) // =>"42 m"
 |      * unit.canonicalValue("42m", true) // =>"42 m"
 | ||||||
|      * unit.canonicalValue("42", true) // =>"42 m"
 |      * unit.canonicalValue("42", true) // =>"42 m"
 | ||||||
|      * unit.canonicalValue("42 m", true) // =>"42 m"
 |      * unit.canonicalValue("42 m", true) // =>"42 m"
 | ||||||
|  | @ -84,7 +84,7 @@ export class Denomination { | ||||||
|      *               human: { |      *               human: { | ||||||
|      *                   en: "meter" |      *                   en: "meter" | ||||||
|      *               } |      *               } | ||||||
|      *           }, "test") |      *           }, false, "test") | ||||||
|      * unit.canonicalValue("42m", true) // =>"42"
 |      * unit.canonicalValue("42m", true) // =>"42"
 | ||||||
|      * unit.canonicalValue("42", true) // =>"42"
 |      * unit.canonicalValue("42", true) // =>"42"
 | ||||||
|      * unit.canonicalValue("42 m", true) // =>"42"
 |      * unit.canonicalValue("42 m", true) // =>"42"
 | ||||||
|  |  | ||||||
|  | @ -389,62 +389,7 @@ export interface LayerConfigJson { | ||||||
|     allowSplit?: boolean |     allowSplit?: boolean | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * In some cases, a value is represented in a certain unit (such as meters for heigt/distance/..., km/h for speed, ...) |      * @see UnitConfigJson | ||||||
|      * |  | ||||||
|      * 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 |  | ||||||
|      * |  | ||||||
|      */ |      */ | ||||||
|     units?: 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 { | export default interface UnitConfigJson { | ||||||
|     /** |     /** | ||||||
|      * Every key from this list will be normalized. |      * Every key from this list will be normalized. | ||||||
|  | @ -11,9 +69,19 @@ export default interface UnitConfigJson { | ||||||
|      */ |      */ | ||||||
|     eraseInvalidValues?: boolean |     eraseInvalidValues?: boolean | ||||||
|     /** |     /** | ||||||
|      * The possible denominations |      * The possible denominations for this unit. | ||||||
|  |      * For length, denominations could be "meter", "kilometer", "miles", "foot" | ||||||
|      */ |      */ | ||||||
|     applicableUnits: DenominationConfigJson[] |     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 { | export interface DenominationConfigJson { | ||||||
|  | @ -28,12 +96,6 @@ export interface DenominationConfigJson { | ||||||
|      */ |      */ | ||||||
|     useIfNoUnitGiven?: boolean | string[] |     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. |      * The canonical value for this denomination which will be added to the value in OSM. | ||||||
|      * e.g. "m" for meters |      * e.g. "m" for meters | ||||||
|  | @ -46,12 +108,15 @@ export interface DenominationConfigJson { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * The canonical denomination in the case that the unit is precisely '1'. |      * 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 |     canonicalDenominationSingular?: string | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * A list of alternative values which can occur in the OSM database - used for parsing. |      * 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[] |     alternativeDenomination?: string[] | ||||||
| 
 | 
 | ||||||
|  | @ -62,16 +127,16 @@ export interface DenominationConfigJson { | ||||||
|      *     "fr": "metre" |      *     "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. |      * The value for humans in the dropdown. This should not use abbreviations and should be translated, e.g. | ||||||
|      * { |      * { | ||||||
|      *     "en": "minute", |      *     "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 '€' |      * 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) { |     static fromJson(json: UnitConfigJson, ctx: string) { | ||||||
|         const appliesTo = json.appliesToKey |         const appliesTo = json.appliesToKey | ||||||
|         for (let i = 0; i < appliesTo.length; i++) { |         for (let i = 0; i < appliesTo.length; i++) { | ||||||
|  | @ -74,14 +112,13 @@ export class Unit { | ||||||
|         } |         } | ||||||
|         // Some keys do have unit handling
 |         // 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( |         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) |         return new Unit(appliesTo, applicable, json.eraseInvalidValues ?? false) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -205,6 +205,7 @@ | ||||||
|         "elevator:width", |         "elevator:width", | ||||||
|         "elevator:depth" |         "elevator:depth" | ||||||
|       ], |       ], | ||||||
|  |       "defaultInput": "cm", | ||||||
|       "applicableUnits": [ |       "applicableUnits": [ | ||||||
|         { |         { | ||||||
|           "canonicalDenomination": "m", |           "canonicalDenomination": "m", | ||||||
|  | @ -221,7 +222,6 @@ | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           "useAsDefaultInput": true, |  | ||||||
|           "canonicalDenomination": "cm", |           "canonicalDenomination": "cm", | ||||||
|           "alternativeDenomination": [ |           "alternativeDenomination": [ | ||||||
|             "centimeter", |             "centimeter", | ||||||
|  |  | ||||||
|  | @ -473,6 +473,7 @@ | ||||||
|         "kerb:height", |         "kerb:height", | ||||||
|         "width" |         "width" | ||||||
|       ], |       ], | ||||||
|  |       "defaultInput": "cm", | ||||||
|       "applicableUnits": [ |       "applicableUnits": [ | ||||||
|         { |         { | ||||||
|           "useIfNoUnitGiven": true, |           "useIfNoUnitGiven": true, | ||||||
|  | @ -489,7 +490,6 @@ | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           "useAsDefaultInput": true, |  | ||||||
|           "canonicalDenomination": "cm", |           "canonicalDenomination": "cm", | ||||||
|           "alternativeDenomination": [ |           "alternativeDenomination": [ | ||||||
|             "centimeter", |             "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", |         "width", | ||||||
|         "_biggest_width" |         "_biggest_width" | ||||||
|       ], |       ], | ||||||
|  |       "defaultUnit": "cm", | ||||||
|       "applicableUnits": [ |       "applicableUnits": [ | ||||||
|         { |         { | ||||||
|           "useIfNoUnitGiven": true, |           "useIfNoUnitGiven": true, | ||||||
|  | @ -79,7 +80,6 @@ | ||||||
|           } |           } | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           "useAsDefaultInput": true, |  | ||||||
|           "canonicalDenomination": "cm", |           "canonicalDenomination": "cm", | ||||||
|           "alternativeDenomination": [ |           "alternativeDenomination": [ | ||||||
|             "centimeter", |             "centimeter", | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ describe("Unit", () => { | ||||||
|                     nl: " megawatt", |                     nl: " megawatt", | ||||||
|                 }, |                 }, | ||||||
|             }, |             }, | ||||||
|  |             false, | ||||||
|             "test" |             "test" | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue