forked from MapComplete/MapComplete
		
	Fix: fix validation of question input; remove some obsolete logging; stabilize output of generate:translations wrt newlines
This commit is contained in:
		
							parent
							
								
									755f905c36
								
							
						
					
					
						commit
						1f39ba9ab5
					
				
					 26 changed files with 7328 additions and 71 deletions
				
			
		|  | @ -15,7 +15,6 @@ export default class BBoxFeatureSource extends StaticFeatureSource { | ||||||
|                     if (mustTouch.data === undefined) { |                     if (mustTouch.data === undefined) { | ||||||
|                         return features |                         return features | ||||||
|                     } |                     } | ||||||
|                     console.log("UPdating touching bbox") |  | ||||||
|                     const box = mustTouch.data |                     const box = mustTouch.data | ||||||
|                     return features.filter((feature) => { |                     return features.filter((feature) => { | ||||||
|                         if (feature.geometry.type === "Point") { |                         if (feature.geometry.type === "Point") { | ||||||
|  |  | ||||||
|  | @ -10,13 +10,11 @@ import Combine from "../../UI/Base/Combine" | ||||||
| import Title from "../../UI/Base/Title" | import Title from "../../UI/Base/Title" | ||||||
| import Link from "../../UI/Base/Link" | import Link from "../../UI/Base/Link" | ||||||
| import List from "../../UI/Base/List" | import List from "../../UI/Base/List" | ||||||
| import { | import {MappingConfigJson, QuestionableTagRenderingConfigJson,} from "./Json/QuestionableTagRenderingConfigJson" | ||||||
|     MappingConfigJson, |  | ||||||
|     QuestionableTagRenderingConfigJson, |  | ||||||
| } from "./Json/QuestionableTagRenderingConfigJson" |  | ||||||
| import {FixedUiElement} from "../../UI/Base/FixedUiElement" | import {FixedUiElement} from "../../UI/Base/FixedUiElement" | ||||||
| import {Paragraph} from "../../UI/Base/Paragraph" | import {Paragraph} from "../../UI/Base/Paragraph" | ||||||
| import Svg from "../../Svg" | import Svg from "../../Svg" | ||||||
|  | import Validators, {ValidatorType} from "../../UI/InputElement/Validators"; | ||||||
| 
 | 
 | ||||||
| export interface Mapping { | export interface Mapping { | ||||||
|     readonly if: UploadableTag |     readonly if: UploadableTag | ||||||
|  | @ -623,13 +621,19 @@ export default class TagRenderingConfig { | ||||||
|      * |      * | ||||||
|      * @param singleSelectedMapping (Only used if multiAnswer == false): the single mapping to apply. Use (mappings.length) for the freeform |      * @param singleSelectedMapping (Only used if multiAnswer == false): the single mapping to apply. Use (mappings.length) for the freeform | ||||||
|      * @param multiSelectedMapping (Only used if multiAnswer == true): all the mappings that must be applied. Set multiSelectedMapping[mappings.length] to use the freeform as well |      * @param multiSelectedMapping (Only used if multiAnswer == true): all the mappings that must be applied. Set multiSelectedMapping[mappings.length] to use the freeform as well | ||||||
|  |      * @param currentProperties: The current properties of the object for which the question should be answered | ||||||
|      */ |      */ | ||||||
|     public constructChangeSpecification( |     public constructChangeSpecification( | ||||||
|         freeformValue: string | undefined, |         freeformValue: string | undefined, | ||||||
|         singleSelectedMapping: number, |         singleSelectedMapping: number, | ||||||
|         multiSelectedMapping: boolean[] | undefined |         multiSelectedMapping: boolean[] | undefined, | ||||||
|  |         currentProperties: Record<string, string> | ||||||
|     ): UploadableTag { |     ): UploadableTag { | ||||||
|         freeformValue = freeformValue?.trim() |         freeformValue = freeformValue?.trim() | ||||||
|  |         const validator = Validators.get(<ValidatorType> this.freeform?.type) | ||||||
|  |         if(validator && freeformValue){ | ||||||
|  |             freeformValue = validator.reformat(freeformValue,() => currentProperties["_country"]) | ||||||
|  |         } | ||||||
|         if (freeformValue === "") { |         if (freeformValue === "") { | ||||||
|             freeformValue = undefined |             freeformValue = undefined | ||||||
|         } |         } | ||||||
|  | @ -666,7 +670,7 @@ export default class TagRenderingConfig { | ||||||
|                 .filter((_, i) => !multiSelectedMapping[i]) |                 .filter((_, i) => !multiSelectedMapping[i]) | ||||||
|                 .map((m) => m.ifnot) |                 .map((m) => m.ifnot) | ||||||
| 
 | 
 | ||||||
|             if (multiSelectedMapping.at(-1)) { |             if (multiSelectedMapping.at(-1) && this.freeform) { | ||||||
|                 // The freeform value was selected as well
 |                 // The freeform value was selected as well
 | ||||||
|                 selectedMappings.push( |                 selectedMappings.push( | ||||||
|                     new And([ |                     new And([ | ||||||
|  | @ -677,22 +681,29 @@ export default class TagRenderingConfig { | ||||||
|             } |             } | ||||||
|             return TagUtils.FlattenMultiAnswer([...selectedMappings, ...unselectedMappings]) |             return TagUtils.FlattenMultiAnswer([...selectedMappings, ...unselectedMappings]) | ||||||
|         } else { |         } else { | ||||||
|             if (singleSelectedMapping === undefined) { |             // Is at least one mapping shown in the answer?
 | ||||||
|                 return undefined |             const someMappingIsShown = this.mappings.some(m => { | ||||||
|             } |                 if(typeof m.hideInAnswer === "boolean"){ | ||||||
|             if (singleSelectedMapping === this.mappings.length) { |                     return !m.hideInAnswer | ||||||
|                 if (freeformValue === undefined) { |  | ||||||
|                     return undefined |  | ||||||
|                 } |                 } | ||||||
|  |                 const isHidden = m.hideInAnswer.matchesProperties(currentProperties) | ||||||
|  |                 return !isHidden | ||||||
|  |             }  ) | ||||||
|  |             // If all mappings are hidden for the current tags, we can safely assume that we should use the freeform key
 | ||||||
|  |             const useFreeform = freeformValue !== undefined && (singleSelectedMapping === this.mappings.length || !someMappingIsShown) | ||||||
|  |             if (useFreeform) { | ||||||
|                 return new And([ |                 return new And([ | ||||||
|                     new Tag(this.freeform.key, freeformValue), |                     new Tag(this.freeform.key, freeformValue), | ||||||
|                     ...(this.freeform.addExtraTags ?? []), |                     ...(this.freeform.addExtraTags ?? []), | ||||||
|                 ]) |                 ]) | ||||||
|             } else { |             } else if(singleSelectedMapping) { | ||||||
|                 return new And([ |                 return new And([ | ||||||
|                     this.mappings[singleSelectedMapping].if, |                     this.mappings[singleSelectedMapping].if, | ||||||
|                     ...(this.mappings[singleSelectedMapping].addExtraTags ?? []), |                     ...(this.mappings[singleSelectedMapping].addExtraTags ?? []), | ||||||
|                 ]) |                 ]) | ||||||
|  |             }else{ | ||||||
|  |                 console.log("TagRenderingConfig.ConstructSpecification has a weird fallback for", {freeformValue, singleSelectedMapping, multiSelectedMapping, currentProperties}) | ||||||
|  |                 return undefined | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -296,7 +296,8 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         this.initActors() |         this.initActors() | ||||||
|         this.drawSpecialLayers(lastClick) |         this.addLastClick(lastClick) | ||||||
|  |         this.drawSpecialLayers() | ||||||
|         this.initHotkeys() |         this.initHotkeys() | ||||||
|         this.miscSetup() |         this.miscSetup() | ||||||
|         console.log("State setup completed", this) |         console.log("State setup completed", this) | ||||||
|  | @ -424,10 +425,9 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|     /** |     /** | ||||||
|      * Add the special layers to the map |      * Add the special layers to the map | ||||||
|      */ |      */ | ||||||
|     private drawSpecialLayers(last_click: LastClickFeatureSource) { |     private drawSpecialLayers() { | ||||||
|         type AddedByDefaultTypes = typeof Constants.added_by_default[number] |         type AddedByDefaultTypes = typeof Constants.added_by_default[number] | ||||||
|         const empty = [] |         const empty = [] | ||||||
|         this.addLastClick(last_click) |  | ||||||
|         /** |         /** | ||||||
|          * A listing which maps the layerId onto the featureSource |          * A listing which maps the layerId onto the featureSource | ||||||
|          */ |          */ | ||||||
|  |  | ||||||
|  | @ -6,29 +6,43 @@ | ||||||
|   import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid"; |   import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||||
|   import { Translation } from "../i18n/Translation"; |   import { Translation } from "../i18n/Translation"; | ||||||
|   import { createEventDispatcher, onDestroy } from "svelte"; |   import { createEventDispatcher, onDestroy } from "svelte"; | ||||||
|  |   import {Validator} from "./Validator"; | ||||||
| 
 | 
 | ||||||
|   export let value: UIEventSource<string>; |   export let value: UIEventSource<string>; | ||||||
|   // Internal state, only copied to 'value' so that no invalid values leak outside |   // Internal state, only copied to 'value' so that no invalid values leak outside | ||||||
|   let _value = new UIEventSource(value.data ?? ""); |   let _value = new UIEventSource(value.data ?? ""); | ||||||
|   onDestroy(value.addCallbackAndRunD(v => _value.setData(v ?? ""))); |   onDestroy(value.addCallbackAndRunD(v => _value.setData(v ?? ""))); | ||||||
|   export let type: ValidatorType; |   export let type: ValidatorType; | ||||||
|   let validator = Validators.get(type); |  | ||||||
|   export let feedback: UIEventSource<Translation> | undefined = undefined; |   export let feedback: UIEventSource<Translation> | undefined = undefined; | ||||||
|  |   export let getCountry: () => string | undefined | ||||||
|  |   let validator : Validator = Validators.get(type) | ||||||
|  |   $: { | ||||||
|  |     // The type changed -> reset some values | ||||||
|  |     validator = Validators.get(type) | ||||||
|  |     _value.setData("") | ||||||
|  |     feedback =  feedback?.setData(validator?.getFeedback(_value.data, getCountry)); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   onDestroy(value.addCallbackAndRun(v => { | ||||||
|  |     if(v === undefined || v === ""){ | ||||||
|  |       _value.setData("") | ||||||
|  |     } | ||||||
|  |   })) | ||||||
|   onDestroy(_value.addCallbackAndRun(v => { |   onDestroy(_value.addCallbackAndRun(v => { | ||||||
|     if (validator.isValid(v)) { |     if (validator.isValid(v, getCountry)) { | ||||||
|       feedback?.setData(undefined); |       feedback?.setData(undefined); | ||||||
|       value.setData(v); |       value.setData(v); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     value.setData(undefined); |     value.setData(undefined); | ||||||
|     feedback?.setData(validator.getFeedback(v)); |     feedback?.setData(validator.getFeedback(v, getCountry)); | ||||||
|   })) |   })) | ||||||
| 
 | 
 | ||||||
|   if (validator === undefined) { |   if (validator === undefined) { | ||||||
|     throw "Not a valid type for a validator:" + type; |     throw "Not a valid type for a validator:" + type; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   const isValid = _value.map(v => validator.isValid(v)); |   const isValid = _value.map(v => validator.isValid(v, getCountry)); | ||||||
| 
 | 
 | ||||||
|   let htmlElem: HTMLInputElement; |   let htmlElem: HTMLInputElement; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,9 +44,8 @@ export abstract class Validator { | ||||||
|     /** |     /** | ||||||
|      * Gets a piece of feedback. By default, validation.<type> will be used, resulting in a generic 'not a valid <type>'. |      * Gets a piece of feedback. By default, validation.<type> will be used, resulting in a generic 'not a valid <type>'. | ||||||
|      * However, inheritors might overwrite this to give more specific feedback |      * However, inheritors might overwrite this to give more specific feedback | ||||||
|      * @param s |  | ||||||
|      */ |      */ | ||||||
|     public getFeedback(s: string): Translation { |     public getFeedback(s: string, requestCountry?: () => string): Translation { | ||||||
|         const tr = Translations.t.validation[this.name] |         const tr = Translations.t.validation[this.name] | ||||||
|         if (tr !== undefined) { |         if (tr !== undefined) { | ||||||
|             return tr["feedback"] |             return tr["feedback"] | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ import { Translation } from "../../i18n/Translation.js" | ||||||
| import Translations from "../../i18n/Translations.js" | import Translations from "../../i18n/Translations.js" | ||||||
| import * as emailValidatorLibrary from "email-validator" | import * as emailValidatorLibrary from "email-validator" | ||||||
| import {Validator} from "../Validator" | import {Validator} from "../Validator" | ||||||
|  | 
 | ||||||
| export default class EmailValidator extends Validator { | export default class EmailValidator extends Validator { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super("email", "An email adress", "email") |         super("email", "An email adress", "email") | ||||||
|  |  | ||||||
|  | @ -1,12 +1,28 @@ | ||||||
| import {parsePhoneNumberFromString} from "libphonenumber-js" | import {parsePhoneNumberFromString} from "libphonenumber-js" | ||||||
| import {Validator} from "../Validator" | import {Validator} from "../Validator" | ||||||
|  | import {Translation} from "../../i18n/Translation"; | ||||||
|  | import Translations from "../../i18n/Translations"; | ||||||
| 
 | 
 | ||||||
| export default class PhoneValidator extends Validator { | export default class PhoneValidator extends Validator { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super("phone", "A phone number", "tel") |         super("phone", "A phone number", "tel") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     isValid(str, country: () => string): boolean { | 
 | ||||||
|  |     getFeedback(s: string, requestCountry?: () => string): Translation { | ||||||
|  |         const tr = Translations.t.validation.phone | ||||||
|  |         const generic = tr.feedback | ||||||
|  |         if(requestCountry){ | ||||||
|  |         const country = requestCountry() | ||||||
|  |             if(country){ | ||||||
|  |                 return  tr.feedbackCountry.Subs({country}) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return generic | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public isValid(str, country: () => string): boolean { | ||||||
|         if (str === undefined) { |         if (str === undefined) { | ||||||
|             return false |             return false | ||||||
|         } |         } | ||||||
|  | @ -20,13 +36,17 @@ export default class PhoneValidator extends Validator { | ||||||
|         return parsePhoneNumberFromString(str, countryCode)?.isValid() ?? false |         return parsePhoneNumberFromString(str, countryCode)?.isValid() ?? false | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     reformat = (str, country: () => string) => { |     public reformat(str, country: () => string) { | ||||||
|         if (str.startsWith("tel:")) { |         if (str.startsWith("tel:")) { | ||||||
|             str = str.substring("tel:".length) |             str = str.substring("tel:".length) | ||||||
|         } |         } | ||||||
|  |         let countryCode = undefined | ||||||
|  |         if(country){ | ||||||
|  |             countryCode = country() | ||||||
|  |         } | ||||||
|         return parsePhoneNumberFromString( |         return parsePhoneNumberFromString( | ||||||
|             str, |             str, | ||||||
|             country()?.toUpperCase() as any |             countryCode?.toUpperCase() as any | ||||||
|         )?.formatInternational() |         )?.formatInternational() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -498,7 +498,7 @@ export class OH { | ||||||
|                 lat: tags._lat, |                 lat: tags._lat, | ||||||
|                 lon: tags._lon, |                 lon: tags._lon, | ||||||
|                 address: { |                 address: { | ||||||
|                     country_code: tags._country.toLowerCase(), |                     country_code: tags._country?.toLowerCase(), | ||||||
|                     state: undefined, |                     state: undefined, | ||||||
|                 }, |                 }, | ||||||
|             }, |             }, | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import { VariableUiElement } from "../Base/VariableUIElement" | ||||||
| import Table from "../Base/Table" | import Table from "../Base/Table" | ||||||
| import { Translation } from "../i18n/Translation" | import { Translation } from "../i18n/Translation" | ||||||
| import { OsmConnection } from "../../Logic/Osm/OsmConnection" | import { OsmConnection } from "../../Logic/Osm/OsmConnection" | ||||||
|  | import Loading from "../Base/Loading"; | ||||||
| 
 | 
 | ||||||
| export default class OpeningHoursVisualization extends Toggle { | export default class OpeningHoursVisualization extends Toggle { | ||||||
|     private static readonly weekdays: Translation[] = [ |     private static readonly weekdays: Translation[] = [ | ||||||
|  | @ -29,6 +30,7 @@ export default class OpeningHoursVisualization extends Toggle { | ||||||
|         prefix = "", |         prefix = "", | ||||||
|         postfix = "" |         postfix = "" | ||||||
|     ) { |     ) { | ||||||
|  |         const country = tags.map(tags => tags._country) | ||||||
|         const ohTable = new VariableUiElement( |         const ohTable = new VariableUiElement( | ||||||
|             tags |             tags | ||||||
|                 .map((tags) => { |                 .map((tags) => { | ||||||
|  | @ -66,12 +68,12 @@ export default class OpeningHoursVisualization extends Toggle { | ||||||
|                             ), |                             ), | ||||||
|                         ]) |                         ]) | ||||||
|                     } |                     } | ||||||
|                 }) |                 }, [country]) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         super( |         super( | ||||||
|             ohTable, |             ohTable, | ||||||
|             Translations.t.general.opening_hours.loadingCountry.Clone(), |             new Loading(Translations.t.general.opening_hours.loadingCountry), | ||||||
|             tags.map((tgs) => tgs._country !== undefined) |             tags.map((tgs) => tgs._country !== undefined) | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  | @ -160,7 +162,7 @@ export default class OpeningHoursVisualization extends Toggle { | ||||||
|         const weekdayStyles = [] |         const weekdayStyles = [] | ||||||
|         for (let i = 0; i < 7; i++) { |         for (let i = 0; i < 7; i++) { | ||||||
|             const day = OpeningHoursVisualization.weekdays[i].Clone() |             const day = OpeningHoursVisualization.weekdays[i].Clone() | ||||||
|             day.SetClass("w-full h-full block") |             day.SetClass("w-full h-full flex") | ||||||
| 
 | 
 | ||||||
|             const rangesForDay = ranges[i].map((range) => |             const rangesForDay = ranges[i].map((range) => | ||||||
|                 OpeningHoursVisualization.CreateRangeElem( |                 OpeningHoursVisualization.CreateRangeElem( | ||||||
|  |  | ||||||
|  | @ -177,6 +177,7 @@ export default class MoveWizard extends Toggle { | ||||||
| 
 | 
 | ||||||
|                 state.featureProperties.getStore(id).ping() |                 state.featureProperties.getStore(id).ping() | ||||||
|                 currentStep.setData("moved") |                 currentStep.setData("moved") | ||||||
|  |                 state.mapProperties.location.setData(loc) | ||||||
|             }) |             }) | ||||||
|             const zoomInFurhter = t.zoomInFurther.SetClass("alert block m-6") |             const zoomInFurhter = t.zoomInFurther.SetClass("alert block m-6") | ||||||
|             return new Combine([ |             return new Combine([ | ||||||
|  |  | ||||||
|  | @ -10,6 +10,8 @@ import Lazy from "../Base/Lazy" | ||||||
| import { OsmServiceState } from "../../Logic/Osm/OsmConnection" | import { OsmServiceState } from "../../Logic/Osm/OsmConnection" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  * @deprecated | ||||||
|  |  * This element is getting stripped and is not used anymore | ||||||
|  * Generates all the questions, one by one |  * Generates all the questions, one by one | ||||||
|  */ |  */ | ||||||
| export default class QuestionBox extends VariableUiElement { | export default class QuestionBox extends VariableUiElement { | ||||||
|  |  | ||||||
|  | @ -19,17 +19,20 @@ | ||||||
| 
 | 
 | ||||||
|   let dispatch = createEventDispatcher<{ "selected" }>(); |   let dispatch = createEventDispatcher<{ "selected" }>(); | ||||||
|   onDestroy(value.addCallbackD(() => {dispatch("selected")})) |   onDestroy(value.addCallbackD(() => {dispatch("selected")})) | ||||||
|  |   function getCountry() { | ||||||
|  |     return tags.data["_country"] | ||||||
|  |   } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class="inline-flex flex-col"> | <div class="inline-flex flex-col"> | ||||||
| 
 | 
 | ||||||
|   {#if config.freeform.inline} |   {#if config.freeform.inline} | ||||||
|     <Inline key={config.freeform.key} {tags} template={config.render}> |     <Inline key={config.freeform.key} {tags} template={config.render}> | ||||||
|       <ValidatedInput {feedback} on:selected={() => dispatch("selected")} |       <ValidatedInput {feedback} {getCountry} on:selected={() => dispatch("selected")} | ||||||
|                       type={config.freeform.type} {value}></ValidatedInput> |                       type={config.freeform.type} {value}></ValidatedInput> | ||||||
|     </Inline> |     </Inline> | ||||||
|   {:else} |   {:else} | ||||||
|     <ValidatedInput {feedback} on:selected={() => dispatch("selected")} |     <ValidatedInput {feedback} {getCountry} on:selected={() => dispatch("selected")} | ||||||
|                     type={config.freeform.type} {value}></ValidatedInput> |                     type={config.freeform.type} {value}></ValidatedInput> | ||||||
| 
 | 
 | ||||||
|   {/if} |   {/if} | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
|   import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid"; |   import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||||
|   import SpecialTranslation from "./SpecialTranslation.svelte"; |   import SpecialTranslation from "./SpecialTranslation.svelte"; | ||||||
|   import TagHint from "../TagHint.svelte"; |   import TagHint from "../TagHint.svelte"; | ||||||
|  |   import Validators from "../../InputElement/Validators"; | ||||||
| 
 | 
 | ||||||
|   export let config: TagRenderingConfig; |   export let config: TagRenderingConfig; | ||||||
|   export let tags: UIEventSource<Record<string, string>>; |   export let tags: UIEventSource<Record<string, string>>; | ||||||
|  | @ -34,9 +35,12 @@ | ||||||
|   let selectedMapping: number = undefined; |   let selectedMapping: number = undefined; | ||||||
|   let checkedMappings: boolean[]; |   let checkedMappings: boolean[]; | ||||||
|   $: { |   $: { | ||||||
|  |     // We received a new config -> reinit | ||||||
|  |     console.log("Initing checkedMappings for", config) | ||||||
|     if (config.mappings?.length > 0 && (checkedMappings === undefined || checkedMappings?.length < config.mappings.length)) { |     if (config.mappings?.length > 0 && (checkedMappings === undefined || checkedMappings?.length < config.mappings.length)) { | ||||||
|       checkedMappings = [...config.mappings.map(_ => false), false /*One element extra in case a freeform value is added*/]; |       checkedMappings = [...config.mappings.map(_ => false), false /*One element extra in case a freeform value is added*/]; | ||||||
|     } |     } | ||||||
|  |     freeformInput.setData(undefined) | ||||||
|   } |   } | ||||||
|   let selectedTags: TagsFilter = undefined; |   let selectedTags: TagsFilter = undefined; | ||||||
| 
 | 
 | ||||||
|  | @ -54,9 +58,10 @@ | ||||||
|   $: { |   $: { | ||||||
|     mappings = config.mappings?.filter(m => !mappingIsHidden(m)); |     mappings = config.mappings?.filter(m => !mappingIsHidden(m)); | ||||||
|     try { |     try { | ||||||
|       selectedTags = config?.constructChangeSpecification($freeformInput, selectedMapping, checkedMappings); |       let freeformInputValue = $freeformInput | ||||||
|  |       selectedTags = config?.constructChangeSpecification(freeformInputValue, selectedMapping, checkedMappings, tags.data); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       console.debug("Could not calculate changeSpecification:", e); |       console.error("Could not calculate changeSpecification:", e); | ||||||
|       selectedTags = undefined; |       selectedTags = undefined; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -99,7 +104,7 @@ | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|     freeformInput.setData(undefined); |     freeformInput.setData(undefined); | ||||||
|     selectedMapping = 0; |     selectedMapping = undefined; | ||||||
|     selectedTags = undefined; |     selectedTags = undefined; | ||||||
| 
 | 
 | ||||||
|     change.CreateChangeDescriptions().then(changes => |     change.CreateChangeDescriptions().then(changes => | ||||||
|  | @ -139,14 +144,14 @@ | ||||||
|         {#each config.mappings as mapping, i (mapping.then)} |         {#each config.mappings as mapping, i (mapping.then)} | ||||||
|           <!-- Even though we have a list of 'mappings' already, we still iterate over the list as to keep the original indices--> |           <!-- Even though we have a list of 'mappings' already, we still iterate over the list as to keep the original indices--> | ||||||
|           {#if !mappingIsHidden(mapping)  } |           {#if !mappingIsHidden(mapping)  } | ||||||
|             <label> |             <label class="flex"> | ||||||
|               <input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id} value={i}> |               <input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id} value={i}> | ||||||
|               <TagRenderingMapping {mapping} {tags} {state} {selectedElement} {layer}></TagRenderingMapping> |               <TagRenderingMapping {mapping} {tags} {state} {selectedElement} {layer}></TagRenderingMapping> | ||||||
|             </label> |             </label> | ||||||
|           {/if} |           {/if} | ||||||
|         {/each} |         {/each} | ||||||
|         {#if config.freeform?.key} |         {#if config.freeform?.key} | ||||||
|           <label> |           <label class="flex"> | ||||||
|             <input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id} |             <input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id} | ||||||
|                    value={config.mappings.length}> |                    value={config.mappings.length}> | ||||||
|             <FreeformInput {config} {tags} feature={selectedElement} value={freeformInput} |             <FreeformInput {config} {tags} feature={selectedElement} value={freeformInput} | ||||||
|  | @ -159,13 +164,14 @@ | ||||||
|       <div class="flex flex-col"> |       <div class="flex flex-col"> | ||||||
|         {#each config.mappings as mapping, i (mapping.then)} |         {#each config.mappings as mapping, i (mapping.then)} | ||||||
|           {#if !mappingIsHidden(mapping)} |           {#if !mappingIsHidden(mapping)} | ||||||
|             <label> |             <label class="flex"> | ||||||
|               <input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+i} bind:checked={checkedMappings[i]}> |               <input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+i} bind:checked={checkedMappings[i]}> | ||||||
|               <TagRenderingMapping {mapping} {tags} {state} {selectedElement}></TagRenderingMapping> |               <TagRenderingMapping {mapping} {tags} {state} {selectedElement}></TagRenderingMapping> | ||||||
|             </label>{/if} |             </label> | ||||||
|  |           {/if} | ||||||
|         {/each} |         {/each} | ||||||
|         {#if config.freeform?.key} |         {#if config.freeform?.key} | ||||||
|           <label> |           <label class="flex"> | ||||||
|             <input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+config.mappings.length} |             <input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+config.mappings.length} | ||||||
|                    bind:checked={checkedMappings[config.mappings.length]}> |                    bind:checked={checkedMappings[config.mappings.length]}> | ||||||
|             <FreeformInput {config} {tags} feature={selectedElement} value={freeformInput} |             <FreeformInput {config} {tags} feature={selectedElement} value={freeformInput} | ||||||
|  | @ -184,7 +190,7 @@ | ||||||
|           <Tr t={Translations.t.general.save}></Tr> |           <Tr t={Translations.t.general.save}></Tr> | ||||||
|         </button> |         </button> | ||||||
|       {:else } |       {:else } | ||||||
|         <div class="w-6 h-6"> |         <div class="inline-flex w-6 h-6"> | ||||||
|           <!-- Invalid value; show an inactive button or something like that--> |           <!-- Invalid value; show an inactive button or something like that--> | ||||||
|           <ExclamationIcon/> |           <ExclamationIcon/> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ import { SearchablePillsSelector } from "../Input/SearchableMappingsSelector" | ||||||
| import { OsmTags } from "../../Models/OsmFeature" | import { OsmTags } from "../../Models/OsmFeature" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  * @deprecated: getting stripped and getting ported | ||||||
|  * Shows the question element. |  * Shows the question element. | ||||||
|  * Note that the value _migh_ already be known, e.g. when selected or when changing the value |  * Note that the value _migh_ already be known, e.g. when selected or when changing the value | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								assets/fonts/Ubuntu-L-normal.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								assets/fonts/Ubuntu-L-normal.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								assets/fonts/Ubuntu-M-normal.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								assets/fonts/Ubuntu-M-normal.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								assets/fonts/UbuntuMono-B-bold.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								assets/fonts/UbuntuMono-B-bold.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -1006,7 +1006,8 @@ | ||||||
|         }, |         }, | ||||||
|         "phone": { |         "phone": { | ||||||
|             "description": "a phone number", |             "description": "a phone number", | ||||||
|             "feedback": "This is not a valid phone number" |             "feedback": "This is not a valid phone number", | ||||||
|  |             "feedbackCountry": "This is not a valid phone number (for country {country})" | ||||||
|         }, |         }, | ||||||
|         "pnat": { |         "pnat": { | ||||||
|             "description": "a positive, whole number", |             "description": "a positive, whole number", | ||||||
|  |  | ||||||
							
								
								
									
										908
									
								
								public/assets/templates/MapComplete-flyer.back.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										908
									
								
								public/assets/templates/MapComplete-flyer.back.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 56 KiB | 
							
								
								
									
										1492
									
								
								public/assets/templates/MapComplete-flyer.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1492
									
								
								public/assets/templates/MapComplete-flyer.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 1.6 MiB | 
							
								
								
									
										2353
									
								
								public/assets/templates/MapComplete-poster-a2.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2353
									
								
								public/assets/templates/MapComplete-poster-a2.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 1.5 MiB | 
							
								
								
									
										2398
									
								
								public/assets/templates/MapComplete-poster-a3.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2398
									
								
								public/assets/templates/MapComplete-poster-a3.svg
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 1.5 MiB | 
							
								
								
									
										7
									
								
								public/assets/templates/Ubuntu-L-normal.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								public/assets/templates/Ubuntu-L-normal.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								public/assets/templates/Ubuntu-M-normal.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								public/assets/templates/Ubuntu-M-normal.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								public/assets/templates/UbuntuMono-B-bold.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								public/assets/templates/UbuntuMono-B-bold.js
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -444,6 +444,7 @@ function removeEmptyString(object: object) { | ||||||
|     } |     } | ||||||
|     return object |     return object | ||||||
| } | } | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Formats the specified file, helps to prevent merge conflicts |  * Formats the specified file, helps to prevent merge conflicts | ||||||
|  * */ |  * */ | ||||||
|  | @ -659,7 +660,8 @@ function mergeLayerTranslations() { | ||||||
|     const layerFiles = ScriptUtils.getLayerFiles() |     const layerFiles = ScriptUtils.getLayerFiles() | ||||||
|     for (const layerFile of layerFiles) { |     for (const layerFile of layerFiles) { | ||||||
|         mergeLayerTranslation(layerFile.parsed, layerFile.path, loadTranslationFilesFrom("layers")) |         mergeLayerTranslation(layerFile.parsed, layerFile.path, loadTranslationFilesFrom("layers")) | ||||||
|         writeFileSync(layerFile.path, JSON.stringify(layerFile.parsed, null, "  ")) // layers use 2 spaces
 |         const endsWithNewline = readFileSync(layerFile.path, {encoding: "utf8"})?.endsWith("\n") ?? true | ||||||
|  |         writeFileSync(layerFile.path, JSON.stringify(layerFile.parsed, null, "  ") + (endsWithNewline ? "\n" : "")) // layers use 2 spaces
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -674,7 +676,8 @@ function mergeThemeTranslations() { | ||||||
| 
 | 
 | ||||||
|         const allTranslations = new TranslationPart() |         const allTranslations = new TranslationPart() | ||||||
|         allTranslations.recursiveAdd(config, themeFile.path) |         allTranslations.recursiveAdd(config, themeFile.path) | ||||||
|         writeFileSync(themeFile.path, JSON.stringify(config, null, "  ")) // Themefiles use 2 spaces
 |         const endsWithNewline = readFileSync(themeFile.path, {encoding: "utf8"})?.endsWith("\n") ?? true | ||||||
|  |         writeFileSync(themeFile.path, JSON.stringify(config, null, "  ") + (endsWithNewline ? "\n" : "")) // Themefiles use 2 spaces
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -693,7 +696,8 @@ if (!themeOverwritesWeblate) { | ||||||
|         questionsPath, |         questionsPath, | ||||||
|         loadTranslationFilesFrom("shared-questions") |         loadTranslationFilesFrom("shared-questions") | ||||||
|     ) |     ) | ||||||
|     writeFileSync(questionsPath, JSON.stringify(questionsParsed, null, "  ")) |     const endsWithNewline = readFileSync(questionsPath, {encoding: "utf8"}).endsWith("\n") | ||||||
|  |     writeFileSync(questionsPath, JSON.stringify(questionsParsed, null, "  ") + (endsWithNewline ? "\n" : "")) | ||||||
| } else { | } else { | ||||||
|     console.log("Ignore weblate") |     console.log("Ignore weblate") | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue