Add input validation
This commit is contained in:
parent
ef593654f4
commit
1488caf362
8 changed files with 66 additions and 17 deletions
|
@ -8,6 +8,7 @@ import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWi
|
||||||
import BikeStationOperator from "../Questions/bike/StationOperator";
|
import BikeStationOperator from "../Questions/bike/StationOperator";
|
||||||
import Translations from "../../UI/i18n/Translations";
|
import Translations from "../../UI/i18n/Translations";
|
||||||
import ParkingOperator from "../Questions/bike/ParkingOperator";
|
import ParkingOperator from "../Questions/bike/ParkingOperator";
|
||||||
|
import {TagRenderingOptions} from "../TagRendering";
|
||||||
|
|
||||||
|
|
||||||
export default class BikeParkings extends LayerDefinition {
|
export default class BikeParkings extends LayerDefinition {
|
||||||
|
@ -27,7 +28,15 @@ export default class BikeParkings extends LayerDefinition {
|
||||||
this.elementsToShow = [
|
this.elementsToShow = [
|
||||||
new ImageCarouselWithUploadConstructor(),
|
new ImageCarouselWithUploadConstructor(),
|
||||||
//new ParkingOperator(),
|
//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;
|
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY;
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,19 @@ import {FixedInputElement} from "../UI/Input/FixedInputElement";
|
||||||
import {RadioButton} from "../UI/Input/RadioButton";
|
import {RadioButton} from "../UI/Input/RadioButton";
|
||||||
import Translations from "../UI/i18n/Translations";
|
import Translations from "../UI/i18n/Translations";
|
||||||
import Locale from "../UI/i18n/Locale";
|
import Locale from "../UI/i18n/Locale";
|
||||||
|
import {FloatField, IntField, StringField} from "../UI/Input/PhoneField";
|
||||||
|
|
||||||
export class TagRenderingOptions implements TagDependantUIElementConstructor {
|
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
|
* Notes: by not giving a 'question', one disables the question form alltogether
|
||||||
*/
|
*/
|
||||||
|
@ -334,13 +344,20 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prepost = Translations.W(freeform.template).InnerRender().split("$");
|
||||||
|
const type = prepost[1];
|
||||||
|
const isValid = TagRenderingOptions.inputValidation[type];
|
||||||
|
|
||||||
const pickString =
|
const pickString =
|
||||||
(string) => {
|
(string: any) => {
|
||||||
if (string === "" || string === undefined) {
|
if (string === "" || string === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
if (!isValid(string)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const tag = new Tag(freeform.key, string);
|
const tag = new Tag(freeform.key, string);
|
||||||
|
|
||||||
if (freeform.extraTags === undefined) {
|
if (freeform.extraTags === undefined) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
@ -369,8 +386,7 @@ class TagRendering extends UIElement implements TagDependantUIElement {
|
||||||
toString: toString
|
toString: toString
|
||||||
});
|
});
|
||||||
|
|
||||||
const prepost = Translations.W(freeform.template).InnerRender().split("$$$");
|
return new InputElementWrapper(prepost[0], textField, prepost[2]);
|
||||||
return new InputElementWrapper(prepost[0], textField, prepost[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,12 @@ import {UIEventSource} from "../UI/UIEventSource";
|
||||||
|
|
||||||
export class QueryParameters {
|
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 knownSources = QueryParameters.init();
|
||||||
|
|
||||||
private static addOrder(key){
|
private static addOrder(key){
|
||||||
if(this.order.indexOf(key) < 0){
|
if(this.order.indexOf(key) < 0){
|
||||||
|
console.log("Adding order", key)
|
||||||
this.order.push(key)
|
this.order.push(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,5 @@ export abstract class InputElement<T> extends UIElement{
|
||||||
|
|
||||||
abstract IsValid(t: T) : boolean;
|
abstract IsValid(t: T) : boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {UIElement} from "../UIElement";
|
import {UIElement} from "../UIElement";
|
||||||
import {UIEventSource} from "../UIEventSource";
|
import {UIEventSource} from "../UIEventSource";
|
||||||
import {InputElement} from "./InputElement";
|
import {InputElement} from "./InputElement";
|
||||||
import {FixedUiElement} from "../Base/FixedUiElement";
|
|
||||||
import Translations from "../i18n/Translations";
|
import Translations from "../i18n/Translations";
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,9 +16,23 @@ export class TextField<T> extends InputElement<T> {
|
||||||
private _fromString?: (string: string) => T;
|
private _fromString?: (string: string) => T;
|
||||||
private _toString: (t: T) => string;
|
private _toString: (t: T) => string;
|
||||||
|
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
|
/**
|
||||||
|
* Shown as placeholder
|
||||||
|
*/
|
||||||
placeholder?: string | UIElement,
|
placeholder?: string | UIElement,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the T to a (canonical) string
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
toString: (t: T) => string,
|
toString: (t: T) => string,
|
||||||
|
/**
|
||||||
|
* Converts the string to a T
|
||||||
|
* Returns undefined if invalid
|
||||||
|
* @param string
|
||||||
|
*/
|
||||||
fromString: (string: string) => T,
|
fromString: (string: string) => T,
|
||||||
value?: UIEventSource<T>
|
value?: UIEventSource<T>
|
||||||
}) {
|
}) {
|
||||||
|
@ -66,9 +79,9 @@ export class TextField<T> extends InputElement<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerRender(): string {
|
InnerRender(): string {
|
||||||
return "<form onSubmit='return false' class='form-text-field'>" +
|
return `<form onSubmit='return false' class='form-text-field'>` +
|
||||||
"<input type='text' placeholder='" + this._placeholder.InnerRender() + "' id='text-" + this.id + "'>" +
|
`<input type='text' placeholder='${this._placeholder.InnerRender()}' id='text-${this.id}'>` +
|
||||||
"</form>";
|
`</form>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerUpdate() {
|
InnerUpdate() {
|
||||||
|
@ -76,6 +89,11 @@ export class TextField<T> extends InputElement<T> {
|
||||||
if (field === null) {
|
if (field === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mappedValue.addCallback((data) => {
|
||||||
|
field.className = this.mappedValue.data !== undefined ? "valid" : "invalid";
|
||||||
|
});
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
field.oninput = () => {
|
field.oninput = () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
|
@ -386,6 +386,10 @@ export default class Translations {
|
||||||
skippedQuestions: new T({
|
skippedQuestions: new T({
|
||||||
en: "Some questions are skipped",
|
en: "Some questions are skipped",
|
||||||
nl: "Sommige vragen zijn overgeslaan"
|
nl: "Sommige vragen zijn overgeslaan"
|
||||||
|
}),
|
||||||
|
number: new T({
|
||||||
|
en: "number",
|
||||||
|
nl: "getal"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,10 @@ form {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invalid {
|
||||||
|
box-shadow: 0 0 10px #ff5353;
|
||||||
|
}
|
||||||
|
|
||||||
#leafletDiv {
|
#leafletDiv {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
10
test.ts
10
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)
|
const f = new IntField().AttachTo("maindiv")
|
||||||
|
f.GetValue().addCallback(console.log)
|
||||||
console.log("Layout is", layout.data)
|
|
||||||
|
|
||||||
window.setTimeout(() => {layout.setData("XXX"), 2000})
|
|
Loading…
Reference in a new issue