From 1488caf36285f97350fc5381400c3c2db4d7db4b Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 23 Jul 2020 17:32:18 +0200 Subject: [PATCH] Add input validation --- Customizations/Layers/BikeParkings.ts | 11 ++++++++++- Customizations/TagRendering.ts | 22 +++++++++++++++++++--- Logic/QueryParameters.ts | 3 ++- UI/Input/InputElement.ts | 3 ++- UI/Input/TextField.ts | 26 ++++++++++++++++++++++---- UI/i18n/Translations.ts | 4 ++++ index.css | 4 ++++ test.ts | 10 +++------- 8 files changed, 66 insertions(+), 17 deletions(-) diff --git a/Customizations/Layers/BikeParkings.ts b/Customizations/Layers/BikeParkings.ts index 3f07869..67b0b89 100644 --- a/Customizations/Layers/BikeParkings.ts +++ b/Customizations/Layers/BikeParkings.ts @@ -8,6 +8,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi import BikeStationOperator from "../Questions/bike/StationOperator"; import Translations from "../../UI/i18n/Translations"; import ParkingOperator from "../Questions/bike/ParkingOperator"; +import {TagRenderingOptions} from "../TagRendering"; export default class BikeParkings extends LayerDefinition { @@ -27,7 +28,15 @@ export default class BikeParkings extends LayerDefinition { this.elementsToShow = [ new ImageCarouselWithUploadConstructor(), //new ParkingOperator(), - new ParkingType() + new ParkingType(), + new TagRenderingOptions({ + question: "How many bicycles fit in this bicycle parking?", + freeform: { + key: "capacity", + renderTemplate: "Place for {capacity} bikes", + template: "$nat$ bikes fit in here" + } + }) ]; this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY; diff --git a/Customizations/TagRendering.ts b/Customizations/TagRendering.ts index a426fa3..ef41c2d 100644 --- a/Customizations/TagRendering.ts +++ b/Customizations/TagRendering.ts @@ -15,9 +15,19 @@ import {FixedInputElement} from "../UI/Input/FixedInputElement"; import {RadioButton} from "../UI/Input/RadioButton"; import Translations from "../UI/i18n/Translations"; import Locale from "../UI/i18n/Locale"; +import {FloatField, IntField, StringField} from "../UI/Input/PhoneField"; export class TagRenderingOptions implements TagDependantUIElementConstructor { + + public static inputValidation = { + "$": (str) => true, + "string": (str) => true, + "int": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)), + "nat": (str) => str.indexOf(".") < 0 && !isNaN(Number(str)) && Number(str) > 0, + "float": (str) => !isNaN(Number(str)), + } + /** * Notes: by not giving a 'question', one disables the question form alltogether */ @@ -334,13 +344,20 @@ class TagRendering extends UIElement implements TagDependantUIElement { return undefined; } + const prepost = Translations.W(freeform.template).InnerRender().split("$"); + const type = prepost[1]; + const isValid = TagRenderingOptions.inputValidation[type]; const pickString = - (string) => { + (string: any) => { if (string === "" || string === undefined) { return undefined; } + if (!isValid(string)) { + return undefined; + } const tag = new Tag(freeform.key, string); + if (freeform.extraTags === undefined) { return tag; } @@ -369,8 +386,7 @@ class TagRendering extends UIElement implements TagDependantUIElement { toString: toString }); - const prepost = Translations.W(freeform.template).InnerRender().split("$$$"); - return new InputElementWrapper(prepost[0], textField, prepost[1]); + return new InputElementWrapper(prepost[0], textField, prepost[2]); } diff --git a/Logic/QueryParameters.ts b/Logic/QueryParameters.ts index 47006c6..5a512fa 100644 --- a/Logic/QueryParameters.ts +++ b/Logic/QueryParameters.ts @@ -5,11 +5,12 @@ import {UIEventSource} from "../UI/UIEventSource"; export class QueryParameters { - private static order: string [] = ["layout","test","zoom","lat","lon"]; + private static order: string [] = ["layout","test","z","lat","lon"]; private static knownSources = QueryParameters.init(); private static addOrder(key){ if(this.order.indexOf(key) < 0){ + console.log("Adding order", key) this.order.push(key) } } diff --git a/UI/Input/InputElement.ts b/UI/Input/InputElement.ts index 8278314..f1e4bb7 100644 --- a/UI/Input/InputElement.ts +++ b/UI/Input/InputElement.ts @@ -8,4 +8,5 @@ export abstract class InputElement extends UIElement{ abstract IsValid(t: T) : boolean; -} \ No newline at end of file +} + diff --git a/UI/Input/TextField.ts b/UI/Input/TextField.ts index f025b28..4074ee5 100644 --- a/UI/Input/TextField.ts +++ b/UI/Input/TextField.ts @@ -1,7 +1,6 @@ import {UIElement} from "../UIElement"; import {UIEventSource} from "../UIEventSource"; import {InputElement} from "./InputElement"; -import {FixedUiElement} from "../Base/FixedUiElement"; import Translations from "../i18n/Translations"; @@ -17,9 +16,23 @@ export class TextField extends InputElement { private _fromString?: (string: string) => T; private _toString: (t: T) => string; + constructor(options: { + /** + * Shown as placeholder + */ placeholder?: string | UIElement, + + /** + * Converts the T to a (canonical) string + * @param t + */ toString: (t: T) => string, + /** + * Converts the string to a T + * Returns undefined if invalid + * @param string + */ fromString: (string: string) => T, value?: UIEventSource }) { @@ -66,9 +79,9 @@ export class TextField extends InputElement { } InnerRender(): string { - return "
" + - "" + - "
"; + return `
` + + `` + + `
`; } InnerUpdate() { @@ -76,6 +89,11 @@ export class TextField extends InputElement { if (field === null) { return; } + + this.mappedValue.addCallback((data) => { + field.className = this.mappedValue.data !== undefined ? "valid" : "invalid"; + }); + const self = this; field.oninput = () => { // @ts-ignore diff --git a/UI/i18n/Translations.ts b/UI/i18n/Translations.ts index 2c75364..0fe30eb 100644 --- a/UI/i18n/Translations.ts +++ b/UI/i18n/Translations.ts @@ -386,6 +386,10 @@ export default class Translations { skippedQuestions: new T({ en: "Some questions are skipped", nl: "Sommige vragen zijn overgeslaan" + }), + number: new T({ + en: "number", + nl: "getal" }) } } diff --git a/index.css b/index.css index c7d5f7b..a9a3e63 100644 --- a/index.css +++ b/index.css @@ -12,6 +12,10 @@ form { display: inline; } +.invalid { + box-shadow: 0 0 10px #ff5353; +} + #leafletDiv { height: 100%; } diff --git a/test.ts b/test.ts index 6489560..c65b01b 100644 --- a/test.ts +++ b/test.ts @@ -1,9 +1,5 @@ -import {QueryParameters} from "./Logic/QueryParameters"; +import {IntField} from "./UI/Input/PhoneField"; -console.log("Hi"); -const layout = QueryParameters.GetQueryParameter("layout").addCallback(console.log) - -console.log("Layout is", layout.data) - -window.setTimeout(() => {layout.setData("XXX"), 2000}) \ No newline at end of file +const f = new IntField().AttachTo("maindiv") +f.GetValue().addCallback(console.log) \ No newline at end of file