forked from MapComplete/MapComplete
		
	A11y: more feedback, add translations, fix some bugs with OH
This commit is contained in:
		
							parent
							
								
									7ac84dd675
								
							
						
					
					
						commit
						46890c7beb
					
				
					 12 changed files with 165 additions and 84 deletions
				
			
		|  | @ -176,7 +176,8 @@ | |||
|                 "en": "Only too-hard tasks", | ||||
|                 "nl": "Enkel foutieve taken" | ||||
|               }, | ||||
|               "osmTags": "mr_taskStatus=Too_hard"            } | ||||
|               "osmTags": "mr_taskStatus=Too_hard" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|       ], | ||||
|  | @ -203,13 +204,16 @@ | |||
|           ], | ||||
|           "iconSize": "40,40", | ||||
|           "anchor": "bottom", | ||||
|           "iconBadges": [{ | ||||
|             "if": "mr_taskStatus=Too_Hard", | ||||
|             "then": "invalid" | ||||
|           },{ | ||||
|             "if": "mr_taskStatus=Fixed", | ||||
|             "then": "confirm" | ||||
|           }] | ||||
|           "iconBadges": [ | ||||
|             { | ||||
|               "if": "mr_taskStatus=Too_Hard", | ||||
|               "then": "invalid" | ||||
|             }, | ||||
|             { | ||||
|               "if": "mr_taskStatus=Fixed", | ||||
|               "then": "confirm" | ||||
|             } | ||||
|           ] | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|  |  | |||
|  | @ -1343,6 +1343,21 @@ | |||
|                     } | ||||
|                 }, | ||||
|                 "question": "What is the relative location of this bicycle parking?" | ||||
|             }, | ||||
|             "fee": { | ||||
|                 "mappings": { | ||||
|                     "0": { | ||||
|                         "then": "One has to <b>pay</b> to use this bicycle parking" | ||||
|                     }, | ||||
|                     "1": { | ||||
|                         "then": "Free to use" | ||||
|                     } | ||||
|                 }, | ||||
|                 "question": "Are these bicycle parkings free to use?" | ||||
|             }, | ||||
|             "operator_phone": { | ||||
|                 "question": "What is the phone number of the operator of this bicycle parking?", | ||||
|                 "questionHint": "One might be able to call this number in case of problems, e.g. to remove unmaintained bicycles" | ||||
|             } | ||||
|         }, | ||||
|         "title": { | ||||
|  |  | |||
|  | @ -1198,6 +1198,21 @@ | |||
|                     } | ||||
|                 }, | ||||
|                 "question": "Wat is de relatieve locatie van deze parking??" | ||||
|             }, | ||||
|             "fee": { | ||||
|                 "mappings": { | ||||
|                     "0": { | ||||
|                         "then": "<b>Betalende</b> fietsparking" | ||||
|                     }, | ||||
|                     "1": { | ||||
|                         "then": "Gratis te gebruiken" | ||||
|                     } | ||||
|                 }, | ||||
|                 "question": "Is deze fietsenstalling gratis te gebruiken?" | ||||
|             }, | ||||
|             "operator_phone": { | ||||
|                 "question": "Wat is het telefoonnummer van de operator van deze fietsenstalling?", | ||||
|                 "questionHint": "Men kan dit nummer bellen om bv. fietswrakken of defecten te melden" | ||||
|             } | ||||
|         }, | ||||
|         "title": { | ||||
|  |  | |||
|  | @ -370,6 +370,26 @@ | |||
|         "useSearch": "Gebruik de zoekfunctie hierboven om meer opties te zien", | ||||
|         "visualFeedback": { | ||||
|             "closestFeaturesAre": "{n} objecten in beeld.", | ||||
|             "directionsAbsolute": { | ||||
|                 "E": "ten oosten", | ||||
|                 "N": "ten noorden", | ||||
|                 "NE": "ten noordoosten", | ||||
|                 "NW": "ten noordwesten", | ||||
|                 "S": "ten zuiden", | ||||
|                 "SE": "ten zuidoosten", | ||||
|                 "SW": "ten zuidwesten", | ||||
|                 "W": "ten westen" | ||||
|             }, | ||||
|             "directionsRelative": { | ||||
|                 "behind": "achter je", | ||||
|                 "left": "links", | ||||
|                 "right": "rechts", | ||||
|                 "sharp_left": "scherp linksaf", | ||||
|                 "sharp_right": "scherp rechtsaf", | ||||
|                 "slight_left": "ietwat links", | ||||
|                 "slight_right": "ietwat rechts", | ||||
|                 "straight": "vooruit" | ||||
|             }, | ||||
|             "east": "Naar het oosten", | ||||
|             "in": "Aan het inzoomen naar zoomlevel {z}", | ||||
|             "islocked": "Bewegen vergrendeld rond je huidige locatie. Duw op de geolocatie-knop om te ontgrendelen.", | ||||
|  | @ -381,6 +401,8 @@ | |||
|             "out": "Aan het uitzoomen naar zoomlevel {z}", | ||||
|             "south": "Naar het zuiden", | ||||
|             "unlocked": "Bewegen ontgrendeld", | ||||
|             "viewportCenterCloseToGps": "De kaart is gecentreerd op je huidige GPS-locatie.", | ||||
|             "viewportCenterDetails": "Het kaartbeeldcentrum is {distance} {bearing} vanaf je huidige locatie.", | ||||
|             "west": "Naar het westen" | ||||
|         }, | ||||
|         "weekdays": { | ||||
|  |  | |||
|  | @ -891,6 +891,11 @@ video { | |||
|   margin-right: 3rem; | ||||
| } | ||||
| 
 | ||||
| .mx-16 { | ||||
|   margin-left: 4rem; | ||||
|   margin-right: 4rem; | ||||
| } | ||||
| 
 | ||||
| .mt-4 { | ||||
|   margin-top: 1rem; | ||||
| } | ||||
|  | @ -1110,10 +1115,6 @@ video { | |||
|   height: fit-content; | ||||
| } | ||||
| 
 | ||||
| .h-16 { | ||||
|   height: 4rem; | ||||
| } | ||||
| 
 | ||||
| .h-0 { | ||||
|   height: 0px; | ||||
| } | ||||
|  | @ -1142,6 +1143,10 @@ video { | |||
|   height: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .h-16 { | ||||
|   height: 4rem; | ||||
| } | ||||
| 
 | ||||
| .h-48 { | ||||
|   height: 12rem; | ||||
| } | ||||
|  | @ -1154,10 +1159,6 @@ video { | |||
|   height: 16rem; | ||||
| } | ||||
| 
 | ||||
| .h-10 { | ||||
|   height: 2.5rem; | ||||
| } | ||||
| 
 | ||||
| .h-80 { | ||||
|   height: 20rem; | ||||
| } | ||||
|  | @ -1170,6 +1171,10 @@ video { | |||
|   height: 5rem; | ||||
| } | ||||
| 
 | ||||
| .h-10 { | ||||
|   height: 2.5rem; | ||||
| } | ||||
| 
 | ||||
| .max-h-12 { | ||||
|   max-height: 3rem; | ||||
| } | ||||
|  | @ -1206,10 +1211,6 @@ video { | |||
|   width: 1.5rem; | ||||
| } | ||||
| 
 | ||||
| .w-16 { | ||||
|   width: 4rem; | ||||
| } | ||||
| 
 | ||||
| .w-screen { | ||||
|   width: 100vw; | ||||
| } | ||||
|  | @ -1244,14 +1245,15 @@ video { | |||
|   width: 2.75rem; | ||||
| } | ||||
| 
 | ||||
| .w-64 { | ||||
|   width: 16rem; | ||||
| } | ||||
| 
 | ||||
| .w-1\/2 { | ||||
|   width: 50%; | ||||
| } | ||||
| 
 | ||||
| .w-max { | ||||
|   width: -webkit-max-content; | ||||
|   width: max-content; | ||||
| } | ||||
| 
 | ||||
| .w-auto { | ||||
|   width: auto; | ||||
| } | ||||
|  | @ -1260,8 +1262,8 @@ video { | |||
|   width: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .w-10 { | ||||
|   width: 2.5rem; | ||||
| .w-16 { | ||||
|   width: 4rem; | ||||
| } | ||||
| 
 | ||||
| .w-min { | ||||
|  | @ -1389,10 +1391,6 @@ video { | |||
|   flex-wrap: wrap-reverse; | ||||
| } | ||||
| 
 | ||||
| .content-start { | ||||
|   align-content: flex-start; | ||||
| } | ||||
| 
 | ||||
| .items-start { | ||||
|   align-items: flex-start; | ||||
| } | ||||
|  | @ -1672,10 +1670,6 @@ video { | |||
|   border-width: 2px; | ||||
| } | ||||
| 
 | ||||
| .border-4 { | ||||
|   border-width: 4px; | ||||
| } | ||||
| 
 | ||||
| .border-x { | ||||
|   border-left-width: 1px; | ||||
|   border-right-width: 1px; | ||||
|  | @ -1842,16 +1836,16 @@ video { | |||
|   padding-right: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .px-1 { | ||||
|   padding-left: 0.25rem; | ||||
|   padding-right: 0.25rem; | ||||
| } | ||||
| 
 | ||||
| .px-4 { | ||||
|   padding-left: 1rem; | ||||
|   padding-right: 1rem; | ||||
| } | ||||
| 
 | ||||
| .px-1 { | ||||
|   padding-left: 0.25rem; | ||||
|   padding-right: 0.25rem; | ||||
| } | ||||
| 
 | ||||
| .px-3 { | ||||
|   padding-left: 0.75rem; | ||||
|   padding-right: 0.75rem; | ||||
|  | @ -1914,6 +1908,10 @@ video { | |||
|   padding-right: 0px; | ||||
| } | ||||
| 
 | ||||
| .pt-1 { | ||||
|   padding-top: 0.25rem; | ||||
| } | ||||
| 
 | ||||
| .pb-10 { | ||||
|   padding-bottom: 2.5rem; | ||||
| } | ||||
|  | @ -1922,10 +1920,6 @@ video { | |||
|   padding-bottom: 0.5rem; | ||||
| } | ||||
| 
 | ||||
| .pt-1 { | ||||
|   padding-top: 0.25rem; | ||||
| } | ||||
| 
 | ||||
| .text-center { | ||||
|   text-align: center; | ||||
| } | ||||
|  | @ -1949,9 +1943,9 @@ video { | |||
|   line-height: 1.75rem; | ||||
| } | ||||
| 
 | ||||
| .text-sm { | ||||
|   font-size: 0.875rem; | ||||
|   line-height: 1.25rem; | ||||
| .text-xs { | ||||
|   font-size: 0.75rem; | ||||
|   line-height: 1rem; | ||||
| } | ||||
| 
 | ||||
| .text-3xl { | ||||
|  | @ -1964,6 +1958,11 @@ video { | |||
|   line-height: 2rem; | ||||
| } | ||||
| 
 | ||||
| .text-sm { | ||||
|   font-size: 0.875rem; | ||||
|   line-height: 1.25rem; | ||||
| } | ||||
| 
 | ||||
| .text-4xl { | ||||
|   font-size: 2.25rem; | ||||
|   line-height: 2.5rem; | ||||
|  | @ -2062,6 +2061,11 @@ video { | |||
|   color: rgb(255 255 255 / var(--tw-text-opacity)); | ||||
| } | ||||
| 
 | ||||
| .text-red-500 { | ||||
|   --tw-text-opacity: 1; | ||||
|   color: rgb(239 68 68 / var(--tw-text-opacity)); | ||||
| } | ||||
| 
 | ||||
| .underline { | ||||
|   text-decoration-line: underline; | ||||
| } | ||||
|  | @ -3023,10 +3027,6 @@ svg.apply-fill path { | |||
|     height: 2rem; | ||||
|   } | ||||
| 
 | ||||
|   .md\:h-16 { | ||||
|     height: 4rem; | ||||
|   } | ||||
| 
 | ||||
|   .md\:w-8 { | ||||
|     width: 2rem; | ||||
|   } | ||||
|  | @ -3035,10 +3035,6 @@ svg.apply-fill path { | |||
|     width: 50%; | ||||
|   } | ||||
| 
 | ||||
|   .md\:w-16 { | ||||
|     width: 4rem; | ||||
|   } | ||||
| 
 | ||||
|   .md\:grid-flow-row { | ||||
|     grid-auto-flow: row; | ||||
|   } | ||||
|  |  | |||
|  | @ -949,11 +949,18 @@ export class GeoOperations { | |||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * GeoOperations.bearingToHuman(0) // => "N"
 | ||||
|      * GeoOperations.bearingToHuman(-10) // => "N"
 | ||||
|      * GeoOperations.bearingToHuman(-180) // => "S"
 | ||||
|      * GeoOperations.bearingToHuman(181) // => "S"
 | ||||
|      * GeoOperations.bearingToHuman(46) // => "NE"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-207) // => "sharp_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-199) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-180) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(-10) // => "straight"
 | ||||
|      * GeoOperations.bearingToHumanRelative(0) // => "straight"
 | ||||
|      * GeoOperations.bearingToHumanRelative(181) // => "behind"
 | ||||
|      * GeoOperations.bearingToHumanRelative(40) // => "slight_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(46) // => "slight_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(95) // => "right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(140) // => "sharp_right"
 | ||||
|      * GeoOperations.bearingToHumanRelative(158) // => "behind"
 | ||||
|      * | ||||
|      */ | ||||
|     public static bearingToHumanRelative( | ||||
|         bearing: number | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ export class Orientation { | |||
|     private _animateFakeMeasurements = false | ||||
| 
 | ||||
|     constructor() { | ||||
|         // this.fakeMeasurements(true)
 | ||||
|         this.fakeMeasurements(false) | ||||
|     } | ||||
| 
 | ||||
|     // noinspection JSUnusedGlobalSymbols
 | ||||
|  |  | |||
|  | @ -84,8 +84,8 @@ | |||
|       const lang = Locale.language.data | ||||
|       let bearingHuman: string | ||||
|       if (compass.data !== undefined) { | ||||
|         console.log("compass:", compass.data) | ||||
|         const bearingRelative = bearing - compass.data | ||||
|         console.log(feature.properties.id, "compass:", compass.data, "relative:", bearingRelative) | ||||
|         const t = relativeDirections[GeoOperations.bearingToHumanRelative(bearingRelative)] | ||||
|         bearingHuman = t.textFor(lang) | ||||
|       } else { | ||||
|  | @ -119,22 +119,27 @@ | |||
| </script> | ||||
| 
 | ||||
| {#if $bearingAndDistGps === undefined} | ||||
|   <button | ||||
|     class={twMerge("soft relative rounded-full p-1", size)} | ||||
|   <!--  | ||||
|   Important: one would expect this to be a button - it certainly behaves as one | ||||
|   However, this breaks the live-reading functionality (at least with Orca+FF), | ||||
|   so we use a 'div' and add on:click manually | ||||
|   --> | ||||
|   <div | ||||
|     class={twMerge("soft relative rounded-full p-1 cursor-pointer border border-black", size)} | ||||
|     on:click={() => focusMap()} | ||||
|     use:ariaLabelStore={label} | ||||
|   > | ||||
|     <Center class="h-7 w-7" /> | ||||
|   </button> | ||||
|   </div> | ||||
| {:else} | ||||
|   <button | ||||
|     class={twMerge("soft relative rounded-full", size)} | ||||
|   <div | ||||
|     class={twMerge("soft relative rounded-full border-black border", size)} | ||||
|     on:click={() => focusMap()} | ||||
|     use:ariaLabelStore={label} | ||||
|   > | ||||
|     <div | ||||
|       class={twMerge( | ||||
|         "absolute top-0 left-0 flex items-center justify-center break-words text-sm", | ||||
|         "absolute top-0 left-0 flex items-center justify-center break-words text-xs cursor-pointer", | ||||
|         size | ||||
|       )} | ||||
|     > | ||||
|  | @ -148,5 +153,5 @@ | |||
|         /> | ||||
|       </div> | ||||
|     {/if} | ||||
|   </button> | ||||
|   </div> | ||||
| {/if} | ||||
|  |  | |||
|  | @ -29,6 +29,6 @@ | |||
|       {state} | ||||
|       {tags} | ||||
|     /> | ||||
|     <DirectionIndicator {feature} {state} /> | ||||
|   </a> | ||||
|   <DirectionIndicator {feature} {state} /> | ||||
| </span> | ||||
|  |  | |||
|  | @ -98,7 +98,12 @@ class SingleBackgroundHandler { | |||
|             addLayerBeforeId = undefined | ||||
|         } | ||||
|         if (!map.getSource(background.id)) { | ||||
|             map.addSource(background.id, RasterLayerHandler.prepareWmsSource(background)) | ||||
|             try { | ||||
|                 map.addSource(background.id, RasterLayerHandler.prepareWmsSource(background)) | ||||
|             } catch (e) { | ||||
|                 console.error("Could not add source", e) | ||||
|                 return | ||||
|             } | ||||
|         } | ||||
|         if (!map.getLayer(background.id)) { | ||||
|             addLayerBeforeId ??= map | ||||
|  | @ -202,14 +207,5 @@ export default class RasterLayerHandler { | |||
|     /** | ||||
|      * Performs all necessary updates | ||||
|      */ | ||||
|     public setBackground() { | ||||
|         this.update().catch((e) => console.error(e)) | ||||
|     } | ||||
| 
 | ||||
|     private async update() { | ||||
|         const map = this._map.data | ||||
|         if (!map) { | ||||
|             return | ||||
|         } | ||||
|     } | ||||
|     public setBackground() {} | ||||
| } | ||||
|  |  | |||
|  | @ -910,6 +910,19 @@ This list will be sorted | |||
| } | ||||
| 
 | ||||
| export class ToTextualDescription { | ||||
|     /** | ||||
|      * const oh = new opening_hours("mon 12:00-16:00") | ||||
|      * const ranges = OH.createRangesForApplicableWeek(oh) | ||||
|      * const tr = ToTextualDescription.createTextualDescriptionFor(oh, ranges.ranges) | ||||
|      * tr.textFor("en") // => "On monday from 12:00 till 16:00"
 | ||||
|      * tr.textFor("nl") // => "Op maandag van 12:00 tot 16:00"
 | ||||
|      * | ||||
|      * const oh = new opening_hours("mon 12:00-16:00; tu 13:00-14:00") | ||||
|      * const ranges = OH.createRangesForApplicableWeek(oh) | ||||
|      * const tr = ToTextualDescription.createTextualDescriptionFor(oh, ranges.ranges) | ||||
|      * tr.textFor("en") // => "On monday from 12:00 till 16:00. On tuesday from 13:00 till 14:00"
 | ||||
|      * tr.textFor("nl") // => "Op maandag van 12:00 tot 16:00. Op dinsdag van 13:00 tot 14:00"
 | ||||
|      */ | ||||
|     public static createTextualDescriptionFor( | ||||
|         oh: opening_hours, | ||||
|         ranges: OpeningRange[][] | ||||
|  | @ -985,10 +998,16 @@ export class ToTextualDescription { | |||
|     } | ||||
| 
 | ||||
|     private static chain(trs: Translation[]): Translation { | ||||
|         let chainer = new TypedTranslation<{ a; b }>({ "*": "{a}. {b}" }) | ||||
|         const languages: Record<string, string> = {} | ||||
|         for (const tr1 of trs) { | ||||
|             for (const supportedLanguage of tr1.SupportedLanguages()) { | ||||
|                 languages[supportedLanguage] = "{a}. {b}" | ||||
|             } | ||||
|         } | ||||
|         let chainer = new TypedTranslation<{ a; b }>(languages) | ||||
|         let tr = trs[0] | ||||
|         for (let i = 1; i < trs.length; i++) { | ||||
|             tr = chainer.Subs({ a: tr, b: trs[i] }) | ||||
|             tr = chainer.PartialSubsTr("a", tr).PartialSubsTr("b", trs[i]) | ||||
|         } | ||||
|         return tr | ||||
|     } | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ import { Translation } from "../i18n/Translation" | |||
| import { OsmConnection } from "../../Logic/Osm/OsmConnection" | ||||
| import Loading from "../Base/Loading" | ||||
| import opening_hours from "opening_hours" | ||||
| import Locale from "../i18n/Locale" | ||||
| 
 | ||||
| export default class OpeningHoursVisualization extends Toggle { | ||||
|     private static readonly weekdays: Translation[] = [ | ||||
|  | @ -53,8 +54,9 @@ export default class OpeningHoursVisualization extends Toggle { | |||
|                     applicableWeek.ranges, | ||||
|                     applicableWeek.startingMonday | ||||
|                 ) | ||||
|                 textual.current.addCallbackAndRunD((descr) => { | ||||
|                     vis.ConstructElement().ariaLabel = descr | ||||
|                 Locale.language.mapD((lng) => { | ||||
|                     console.log("Setting OH description to", lng, textual) | ||||
|                     vis.ConstructElement().ariaLabel = textual.textFor(lng) | ||||
|                 }) | ||||
|                 return vis | ||||
|             }) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue