diff --git a/langs/en.json b/langs/en.json index ff60ed212..842cb8ce5 100644 --- a/langs/en.json +++ b/langs/en.json @@ -847,6 +847,7 @@ }, "tooLong": "The text is too long, at most 255 characters are allowed. You have {count} characters now.", "url": { + "aggregator": "{host} is a third-party aggregator website. If possible, search the official website.", "description": "link to a website", "feedback": "This is not a valid web address" }, diff --git a/langs/nl.json b/langs/nl.json index e7656fec0..322381062 100644 --- a/langs/nl.json +++ b/langs/nl.json @@ -703,6 +703,7 @@ }, "tooLong": "Deze tekst is te lang. De tekst heeft {count} lettertekens, er mogen maximaal 255 letters zijn", "url": { + "aggregator": "{host} is een aggregator-website. Gebruik de officiele website indien mogelijk.", "description": "een link naar een webpagina", "feedback": "Dit is geen geldige link" }, diff --git a/src/UI/InputElement/ValidatedInput.svelte b/src/UI/InputElement/ValidatedInput.svelte index a13c355d3..30d023f6e 100644 --- a/src/UI/InputElement/ValidatedInput.svelte +++ b/src/UI/InputElement/ValidatedInput.svelte @@ -85,13 +85,12 @@ feedback?.setData(undefined) return } + feedback?.setData(validator?.getFeedback(v, getCountry)) if (!validator?.isValid(v, getCountry)) { - feedback?.setData(validator?.getFeedback(v, getCountry)) value.setData(undefined) return } - feedback?.setData(undefined) if (selectedUnit.data) { value.setData(unit.toOsm(v, selectedUnit.data)) } else { diff --git a/src/UI/InputElement/Validators/UrlValidator.ts b/src/UI/InputElement/Validators/UrlValidator.ts index c504a07ca..b4c671c97 100644 --- a/src/UI/InputElement/Validators/UrlValidator.ts +++ b/src/UI/InputElement/Validators/UrlValidator.ts @@ -1,16 +1,30 @@ import { Validator } from "../Validator" +import { Translation } from "../../i18n/Translation" +import Translations from "../../i18n/Translations" export default class UrlValidator extends Validator { private readonly _forceHttps: boolean + + private static readonly aggregatorWebsites = new Set([ + "booking.com", + "hotel-details-guide.com", "tripingguide.com", + "tripadvisor.com", "tripadvisor.co.uk", "tripadvisor.com.au", + ]) + constructor(name?: string, explanation?: string, forceHttps?: boolean) { super( name ?? "url", explanation ?? - "The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed", - "url" + "The validatedTextField will format URLs to always be valid and have a https://-header (even though the 'https'-part will be hidden from the user. Furthermore, some tracking parameters will be removed", + "url", ) this._forceHttps = forceHttps ?? false } + + /** + * + * new UrlValidator().reformat("https://example.com/page?fbclid=123456&utm_source=mastodon") // => "https://example.com/page" + */ reformat(str: string): string { try { let url: URL @@ -63,6 +77,33 @@ export default class UrlValidator extends Validator { } } + /** + * + * const v = new UrlValidator() + * v.getFeedback("example.").textFor("en") // => "This is not a valid web address" + * v.getFeedback("https://booking.com/some-hotel.html").textFor("en").indexOf("search the official website") > 0 // => true + * + */ + getFeedback(s: string, getCountry?: () => string): Translation | undefined { + const upstream = super.getFeedback(s, getCountry) + if (upstream) { + return upstream + } + /* + Upstream calls 'isValid', which checks if it is an actual URL. + If we reach this point, we can safely assume 'new URL' will work + */ + const url = new URL(s) + let host = url.host.toLowerCase() + if (host.startsWith("www.")) { + host = host.slice(4) + } + if (UrlValidator.aggregatorWebsites.has(host)) { + return Translations.t.validation.url.aggregator.Subs({ host }) + } + return undefined + } + isValid(str: string): boolean { try { if (