forked from MapComplete/MapComplete
Studio: WIP
This commit is contained in:
parent
04ecdad1bb
commit
903e168a89
62 changed files with 19152 additions and 123399 deletions
20
src/UI/InputElement/Helpers/SimpleTagInput.svelte
Normal file
20
src/UI/InputElement/Helpers/SimpleTagInput.svelte
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<script lang="ts">/**
|
||||
* Input helper to create a tag. The tag is JSON-encoded
|
||||
*/
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource";
|
||||
import BasicTagInput from "../../Studio/TagInput/BasicTagInput.svelte";
|
||||
|
||||
export let value: UIEventSource<undefined | string>;
|
||||
export let uploadableOnly: boolean;
|
||||
export let overpassSupportNeeded: boolean;
|
||||
|
||||
/**
|
||||
* Only show the taginfo-statistics if they are suspicious (thus: less then 250 entries)
|
||||
*/
|
||||
export let silent: boolean = false;
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<BasicTagInput {overpassSupportNeeded} {silent} tag={value} {uploadableOnly} />
|
||||
33
src/UI/InputElement/Helpers/TagInput.svelte
Normal file
33
src/UI/InputElement/Helpers/TagInput.svelte
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<script lang="ts">/**
|
||||
* Input helper to create a tag. The tag is JSON-encoded
|
||||
*/
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource";
|
||||
import type { TagConfigJson } from "../../../Models/ThemeConfig/Json/TagConfigJson";
|
||||
import FullTagInput from "../../Studio/TagInput/FullTagInput.svelte";
|
||||
|
||||
export let value: UIEventSource<undefined | string>;
|
||||
export let uploadableOnly: boolean;
|
||||
export let overpassSupportNeeded: boolean;
|
||||
|
||||
/**
|
||||
* Only show the taginfo-statistics if they are suspicious (thus: less then 250 entries)
|
||||
*/
|
||||
export let silent: boolean = false;
|
||||
|
||||
let tag: UIEventSource<string | TagConfigJson> = value.sync(s => {
|
||||
try {
|
||||
return JSON.parse(s);
|
||||
} catch (e) {
|
||||
return s;
|
||||
}
|
||||
}, [], t => {
|
||||
if(typeof t === "string"){
|
||||
return t
|
||||
}
|
||||
return JSON.stringify(t);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<FullTagInput {overpassSupportNeeded} {silent} {tag} {uploadableOnly} />
|
||||
|
|
@ -15,6 +15,8 @@ import { Feature } from "geojson"
|
|||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import ImageHelper from "./Helpers/ImageHelper.svelte"
|
||||
import TranslationInput from "./Helpers/TranslationInput.svelte"
|
||||
import TagInput from "./Helpers/TagInput.svelte"
|
||||
import SimpleTagInput from "./Helpers/SimpleTagInput.svelte"
|
||||
|
||||
export interface InputHelperProperties {
|
||||
/**
|
||||
|
|
@ -59,9 +61,11 @@ export default class InputHelpers {
|
|||
wikidata: InputHelpers.constructWikidataHelper,
|
||||
image: (value) => new SvelteUIElement(ImageHelper, { value }),
|
||||
translation: (value) => new SvelteUIElement(TranslationInput, { value }),
|
||||
tag: (value) => new SvelteUIElement(TagInput, { value }),
|
||||
simple_tag: (value) => new SvelteUIElement(SimpleTagInput, { value }),
|
||||
} as const
|
||||
|
||||
public static hideInputField : string[] = ["translation"]
|
||||
public static hideInputField: string[] = ["translation", "simple_tag", "tag"]
|
||||
|
||||
/**
|
||||
* Constructs a mapProperties-object for the given properties.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import BaseUIElement from "../BaseUIElement";
|
||||
import { Translation } from "../i18n/Translation";
|
||||
import Translations from "../i18n/Translations";
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import Translations from "../i18n/Translations"
|
||||
|
||||
/**
|
||||
* A 'TextFieldValidator' contains various methods to check and cleanup an entered value or to give feedback.
|
||||
|
|
@ -16,13 +16,23 @@ export abstract class Validator {
|
|||
/**
|
||||
* What HTML-inputmode to use
|
||||
*/
|
||||
public readonly inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'
|
||||
public readonly inputmode?:
|
||||
| "none"
|
||||
| "text"
|
||||
| "tel"
|
||||
| "url"
|
||||
| "email"
|
||||
| "numeric"
|
||||
| "decimal"
|
||||
| "search"
|
||||
public readonly textArea: boolean
|
||||
|
||||
public readonly isMeta?: boolean
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
explanation: string | BaseUIElement,
|
||||
inputmode?: 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search',
|
||||
inputmode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search",
|
||||
textArea?: false | boolean
|
||||
) {
|
||||
this.name = name
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import ImageUrlValidator from "./Validators/ImageUrlValidator"
|
|||
import TagKeyValidator from "./Validators/TagKeyValidator"
|
||||
import TranslationValidator from "./Validators/TranslationValidator"
|
||||
import FediverseValidator from "./Validators/FediverseValidator"
|
||||
import IconValidator from "./Validators/IconValidator"
|
||||
import TagValidator from "./Validators/TagValidator"
|
||||
|
||||
export type ValidatorType = (typeof Validators.availableTypes)[number]
|
||||
|
||||
|
|
@ -48,7 +50,9 @@ export default class Validators {
|
|||
"simple_tag",
|
||||
"key",
|
||||
"translation",
|
||||
"icon",
|
||||
"fediverse",
|
||||
"tag",
|
||||
] as const
|
||||
|
||||
public static readonly AllValidators: ReadonlyArray<Validator> = [
|
||||
|
|
@ -70,20 +74,15 @@ export default class Validators {
|
|||
new ColorValidator(),
|
||||
new ImageUrlValidator(),
|
||||
new SimpleTagValidator(),
|
||||
new TagValidator(),
|
||||
new TagKeyValidator(),
|
||||
new TranslationValidator(),
|
||||
new IconValidator(),
|
||||
new FediverseValidator(),
|
||||
]
|
||||
|
||||
private static _byType = Validators._byTypeConstructor()
|
||||
|
||||
private static _byTypeConstructor(): Map<ValidatorType, Validator> {
|
||||
const map = new Map<ValidatorType, Validator>()
|
||||
for (const validator of Validators.AllValidators) {
|
||||
map.set(<ValidatorType>validator.name, validator)
|
||||
}
|
||||
return map
|
||||
}
|
||||
public static HelpText(): BaseUIElement {
|
||||
const explanations: BaseUIElement[] = Validators.AllValidators.map((type) =>
|
||||
new Combine([new Title(type.name, 3), type.explanation]).SetClass("flex flex-col")
|
||||
|
|
@ -95,6 +94,14 @@ export default class Validators {
|
|||
]).SetClass("flex flex-col")
|
||||
}
|
||||
|
||||
private static _byTypeConstructor(): Map<ValidatorType, Validator> {
|
||||
const map = new Map<ValidatorType, Validator>()
|
||||
for (const validator of Validators.AllValidators) {
|
||||
map.set(<ValidatorType>validator.name, validator)
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
static get(type: ValidatorType): Validator {
|
||||
return Validators._byType.get(type)
|
||||
}
|
||||
|
|
|
|||
46
src/UI/InputElement/Validators/IconValidator.ts
Normal file
46
src/UI/InputElement/Validators/IconValidator.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { Validator } from "../Validator"
|
||||
import { Translation } from "../../i18n/Translation"
|
||||
import licenses from "../../../assets/generated/license_info.json"
|
||||
import { Utils } from "../../../Utils"
|
||||
|
||||
export default class IconValidator extends Validator {
|
||||
private static allLicenses = new Set(licenses.map((l) => l.path))
|
||||
private static allLicensesArr = Array.from(IconValidator.allLicenses)
|
||||
public static readonly isMeta = true
|
||||
constructor() {
|
||||
super("icon", "Makes sure that a valid .svg-path is added")
|
||||
}
|
||||
|
||||
getFeedback(s: string, getCountry, sloppy?: boolean): Translation | undefined {
|
||||
if (!s.startsWith("http")) {
|
||||
if (!IconValidator.allLicenses.has(s)) {
|
||||
const close = sloppy
|
||||
? []
|
||||
: Utils.sortedByLevenshteinDistance(
|
||||
s.substring(s.lastIndexOf("/")),
|
||||
IconValidator.allLicensesArr,
|
||||
(s) => s.substring(s.lastIndexOf("/"))
|
||||
).slice(0, 5)
|
||||
return new Translation(
|
||||
[
|
||||
`Unkown builtin icon ${s}, perhaps you meant one of: <ul>`,
|
||||
...close.map(
|
||||
(item) =>
|
||||
`<li><span class="flex justify-start"> <img src='${item}' class="w-6 h-6"/>${item}</span></li>`
|
||||
),
|
||||
"</ul>",
|
||||
].join("")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!s.endsWith(".svg")) {
|
||||
return new Translation("An icon should end with `.svg`")
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
isValid(key: string, getCountry?: () => string): boolean {
|
||||
return this.getFeedback(key, getCountry, true) === undefined
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ import { Translation } from "../../i18n/Translation"
|
|||
|
||||
export default class ImageUrlValidator extends UrlValidator {
|
||||
private static readonly allowedExtensions = ["jpg", "jpeg", "svg", "png"]
|
||||
public readonly isMeta = true
|
||||
|
||||
constructor() {
|
||||
super(
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import TagKeyValidator from "./TagKeyValidator"
|
|||
*/
|
||||
export default class SimpleTagValidator extends Validator {
|
||||
private static readonly KeyValidator = new TagKeyValidator()
|
||||
|
||||
public readonly isMeta = true
|
||||
constructor() {
|
||||
super(
|
||||
"simple_tag",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import { Translation } from "../../i18n/Translation"
|
|||
import Translations from "../../i18n/Translations"
|
||||
|
||||
export default class TagKeyValidator extends Validator {
|
||||
|
||||
public readonly isMeta = true
|
||||
constructor() {
|
||||
super("key", "Validates a key, mostly that no weird characters are used")
|
||||
}
|
||||
|
|
|
|||
24
src/UI/InputElement/Validators/TagValidator.ts
Normal file
24
src/UI/InputElement/Validators/TagValidator.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Validator } from "../Validator"
|
||||
import { Translation } from "../../i18n/Translation"
|
||||
import Translations from "../../i18n/Translations"
|
||||
import TagKeyValidator from "./TagKeyValidator"
|
||||
import SimpleTagValidator from "./SimpleTagValidator"
|
||||
|
||||
/**
|
||||
* Checks that the input conforms a JSON-encoded tag expression or a simpleTag`key=value`,
|
||||
*/
|
||||
export default class TagValidator extends Validator {
|
||||
|
||||
public readonly isMeta = true
|
||||
constructor() {
|
||||
super("tag", "A simple tag of the format `key=value` OR a tagExpression")
|
||||
}
|
||||
|
||||
getFeedback(tag: string, _): Translation | undefined {
|
||||
return undefined
|
||||
}
|
||||
|
||||
isValid(tag: string, _): boolean {
|
||||
return this.getFeedback(tag, _) === undefined
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { Validator } from "../Validator"
|
||||
|
||||
export default class TranslationValidator extends Validator {
|
||||
|
||||
public readonly isMeta = true
|
||||
constructor() {
|
||||
super("translation", "Makes sure the the string is of format `Record<string, string>` ")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue