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
|
@ -6,29 +6,43 @@
|
|||
import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid";
|
||||
import { Translation } from "../i18n/Translation";
|
||||
import { createEventDispatcher, onDestroy } from "svelte";
|
||||
import {Validator} from "./Validator";
|
||||
|
||||
export let value: UIEventSource<string>;
|
||||
// Internal state, only copied to 'value' so that no invalid values leak outside
|
||||
let _value = new UIEventSource(value.data ?? "");
|
||||
onDestroy(value.addCallbackAndRunD(v => _value.setData(v ?? "")));
|
||||
export let type: ValidatorType;
|
||||
let validator = Validators.get(type);
|
||||
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 => {
|
||||
if (validator.isValid(v)) {
|
||||
if (validator.isValid(v, getCountry)) {
|
||||
feedback?.setData(undefined);
|
||||
value.setData(v);
|
||||
return;
|
||||
}
|
||||
value.setData(undefined);
|
||||
feedback?.setData(validator.getFeedback(v));
|
||||
feedback?.setData(validator.getFeedback(v, getCountry));
|
||||
}))
|
||||
|
||||
if (validator === undefined) {
|
||||
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;
|
||||
|
||||
|
|
|
@ -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>'.
|
||||
* 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]
|
||||
if (tr !== undefined) {
|
||||
return tr["feedback"]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Translation } from "../../i18n/Translation.js"
|
||||
import {Translation} from "../../i18n/Translation.js"
|
||||
import Translations from "../../i18n/Translations.js"
|
||||
import * as emailValidatorLibrary from "email-validator"
|
||||
import { Validator } from "../Validator"
|
||||
import {Validator} from "../Validator"
|
||||
|
||||
export default class EmailValidator extends Validator {
|
||||
constructor() {
|
||||
super("email", "An email adress", "email")
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
import { parsePhoneNumberFromString } from "libphonenumber-js"
|
||||
import { Validator } from "../Validator"
|
||||
import {parsePhoneNumberFromString} from "libphonenumber-js"
|
||||
import {Validator} from "../Validator"
|
||||
import {Translation} from "../../i18n/Translation";
|
||||
import Translations from "../../i18n/Translations";
|
||||
|
||||
export default class PhoneValidator extends Validator {
|
||||
constructor() {
|
||||
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) {
|
||||
return false
|
||||
}
|
||||
|
@ -20,13 +36,17 @@ export default class PhoneValidator extends Validator {
|
|||
return parsePhoneNumberFromString(str, countryCode)?.isValid() ?? false
|
||||
}
|
||||
|
||||
reformat = (str, country: () => string) => {
|
||||
public reformat(str, country: () => string) {
|
||||
if (str.startsWith("tel:")) {
|
||||
str = str.substring("tel:".length)
|
||||
}
|
||||
let countryCode = undefined
|
||||
if(country){
|
||||
countryCode = country()
|
||||
}
|
||||
return parsePhoneNumberFromString(
|
||||
str,
|
||||
country()?.toUpperCase() as any
|
||||
countryCode?.toUpperCase() as any
|
||||
)?.formatInternational()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -498,7 +498,7 @@ export class OH {
|
|||
lat: tags._lat,
|
||||
lon: tags._lon,
|
||||
address: {
|
||||
country_code: tags._country.toLowerCase(),
|
||||
country_code: tags._country?.toLowerCase(),
|
||||
state: undefined,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ import { VariableUiElement } from "../Base/VariableUIElement"
|
|||
import Table from "../Base/Table"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Loading from "../Base/Loading";
|
||||
|
||||
export default class OpeningHoursVisualization extends Toggle {
|
||||
private static readonly weekdays: Translation[] = [
|
||||
|
@ -29,6 +30,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
prefix = "",
|
||||
postfix = ""
|
||||
) {
|
||||
const country = tags.map(tags => tags._country)
|
||||
const ohTable = new VariableUiElement(
|
||||
tags
|
||||
.map((tags) => {
|
||||
|
@ -66,12 +68,12 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
),
|
||||
])
|
||||
}
|
||||
})
|
||||
}, [country])
|
||||
)
|
||||
|
||||
super(
|
||||
ohTable,
|
||||
Translations.t.general.opening_hours.loadingCountry.Clone(),
|
||||
new Loading(Translations.t.general.opening_hours.loadingCountry),
|
||||
tags.map((tgs) => tgs._country !== undefined)
|
||||
)
|
||||
}
|
||||
|
@ -160,7 +162,7 @@ export default class OpeningHoursVisualization extends Toggle {
|
|||
const weekdayStyles = []
|
||||
for (let i = 0; i < 7; i++) {
|
||||
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) =>
|
||||
OpeningHoursVisualization.CreateRangeElem(
|
||||
|
|
|
@ -177,6 +177,7 @@ export default class MoveWizard extends Toggle {
|
|||
|
||||
state.featureProperties.getStore(id).ping()
|
||||
currentStep.setData("moved")
|
||||
state.mapProperties.location.setData(loc)
|
||||
})
|
||||
const zoomInFurhter = t.zoomInFurther.SetClass("alert block m-6")
|
||||
return new Combine([
|
||||
|
|
|
@ -10,6 +10,8 @@ import Lazy from "../Base/Lazy"
|
|||
import { OsmServiceState } from "../../Logic/Osm/OsmConnection"
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* This element is getting stripped and is not used anymore
|
||||
* Generates all the questions, one by one
|
||||
*/
|
||||
export default class QuestionBox extends VariableUiElement {
|
||||
|
|
|
@ -19,17 +19,20 @@
|
|||
|
||||
let dispatch = createEventDispatcher<{ "selected" }>();
|
||||
onDestroy(value.addCallbackD(() => {dispatch("selected")}))
|
||||
function getCountry() {
|
||||
return tags.data["_country"]
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="inline-flex flex-col">
|
||||
|
||||
{#if config.freeform.inline}
|
||||
<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>
|
||||
</Inline>
|
||||
{:else}
|
||||
<ValidatedInput {feedback} on:selected={() => dispatch("selected")}
|
||||
<ValidatedInput {feedback} {getCountry} on:selected={() => dispatch("selected")}
|
||||
type={config.freeform.type} {value}></ValidatedInput>
|
||||
|
||||
{/if}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import { ExclamationIcon } from "@rgossiaux/svelte-heroicons/solid";
|
||||
import SpecialTranslation from "./SpecialTranslation.svelte";
|
||||
import TagHint from "../TagHint.svelte";
|
||||
import Validators from "../../InputElement/Validators";
|
||||
|
||||
export let config: TagRenderingConfig;
|
||||
export let tags: UIEventSource<Record<string, string>>;
|
||||
|
@ -34,9 +35,12 @@
|
|||
let selectedMapping: number = undefined;
|
||||
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)) {
|
||||
checkedMappings = [...config.mappings.map(_ => false), false /*One element extra in case a freeform value is added*/];
|
||||
}
|
||||
freeformInput.setData(undefined)
|
||||
}
|
||||
let selectedTags: TagsFilter = undefined;
|
||||
|
||||
|
@ -54,9 +58,10 @@
|
|||
$: {
|
||||
mappings = config.mappings?.filter(m => !mappingIsHidden(m));
|
||||
try {
|
||||
selectedTags = config?.constructChangeSpecification($freeformInput, selectedMapping, checkedMappings);
|
||||
let freeformInputValue = $freeformInput
|
||||
selectedTags = config?.constructChangeSpecification(freeformInputValue, selectedMapping, checkedMappings, tags.data);
|
||||
} catch (e) {
|
||||
console.debug("Could not calculate changeSpecification:", e);
|
||||
console.error("Could not calculate changeSpecification:", e);
|
||||
selectedTags = undefined;
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +104,7 @@
|
|||
}
|
||||
);
|
||||
freeformInput.setData(undefined);
|
||||
selectedMapping = 0;
|
||||
selectedMapping = undefined;
|
||||
selectedTags = undefined;
|
||||
|
||||
change.CreateChangeDescriptions().then(changes =>
|
||||
|
@ -139,14 +144,14 @@
|
|||
{#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-->
|
||||
{#if !mappingIsHidden(mapping) }
|
||||
<label>
|
||||
<label class="flex">
|
||||
<input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id} value={i}>
|
||||
<TagRenderingMapping {mapping} {tags} {state} {selectedElement} {layer}></TagRenderingMapping>
|
||||
</label>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if config.freeform?.key}
|
||||
<label>
|
||||
<label class="flex">
|
||||
<input type="radio" bind:group={selectedMapping} name={"mappings-radio-"+config.id}
|
||||
value={config.mappings.length}>
|
||||
<FreeformInput {config} {tags} feature={selectedElement} value={freeformInput}
|
||||
|
@ -159,13 +164,14 @@
|
|||
<div class="flex flex-col">
|
||||
{#each config.mappings as mapping, i (mapping.then)}
|
||||
{#if !mappingIsHidden(mapping)}
|
||||
<label>
|
||||
<label class="flex">
|
||||
<input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+i} bind:checked={checkedMappings[i]}>
|
||||
<TagRenderingMapping {mapping} {tags} {state} {selectedElement}></TagRenderingMapping>
|
||||
</label>{/if}
|
||||
</label>
|
||||
{/if}
|
||||
{/each}
|
||||
{#if config.freeform?.key}
|
||||
<label>
|
||||
<label class="flex">
|
||||
<input type="checkbox" name={"mappings-checkbox-"+config.id+"-"+config.mappings.length}
|
||||
bind:checked={checkedMappings[config.mappings.length]}>
|
||||
<FreeformInput {config} {tags} feature={selectedElement} value={freeformInput}
|
||||
|
@ -184,7 +190,7 @@
|
|||
<Tr t={Translations.t.general.save}></Tr>
|
||||
</button>
|
||||
{: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-->
|
||||
<ExclamationIcon/>
|
||||
</div>
|
||||
|
|
|
@ -29,6 +29,7 @@ import { SearchablePillsSelector } from "../Input/SearchableMappingsSelector"
|
|||
import { OsmTags } from "../../Models/OsmFeature"
|
||||
|
||||
/**
|
||||
* @deprecated: getting stripped and getting ported
|
||||
* Shows the question element.
|
||||
* Note that the value _migh_ already be known, e.g. when selected or when changing the value
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue