Improve URL handling: typing http(s) is not needed anymore for URLs
This commit is contained in:
parent
c6b1ef4a71
commit
057b4a3192
2 changed files with 111 additions and 45 deletions
|
@ -22,12 +22,18 @@ import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
|
|||
import Table from "../Base/Table";
|
||||
import Combine from "../Base/Combine";
|
||||
import Title from "../Base/Title";
|
||||
import InputElementMap from "./InputElementMap";
|
||||
|
||||
interface TextFieldDef {
|
||||
name: string,
|
||||
explanation: string,
|
||||
isValid: ((s: string, country?: () => string) => boolean),
|
||||
reformat?: ((s: string, country?: () => string) => string),
|
||||
/**
|
||||
* Modification to make before the string is uploaded to OSM
|
||||
*/
|
||||
postprocess?: (s: string) => string;
|
||||
undoPostprocess?: (s: string) => string;
|
||||
inputHelper?: (value: UIEventSource<string>, options?: {
|
||||
location: [number, number],
|
||||
mapBackgroundLayer?: UIEventSource<any>,
|
||||
|
@ -187,6 +193,85 @@ class OpeningHoursTextField implements TextFieldDef {
|
|||
return new OpeningHoursInput(value, prefix, postfix)
|
||||
}
|
||||
}
|
||||
|
||||
class UrlTextfieldDef implements TextFieldDef {
|
||||
|
||||
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"
|
||||
inputmode: "url"
|
||||
|
||||
postprocess(str: string) {
|
||||
if (str === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (!str.startsWith("http://") || !str.startsWith("https://")) {
|
||||
return "https://" + str
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
undoPostprocess(str: string) {
|
||||
if (str === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (str.startsWith("http://")) {
|
||||
return str.substr("http://".length)
|
||||
}
|
||||
if (str.startsWith("https://")) {
|
||||
return str.substr("https://".length)
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
reformat(str: string): string {
|
||||
try {
|
||||
let url: URL
|
||||
str = str.toLowerCase()
|
||||
if (!str.startsWith("http://") && !str.startsWith("https://") && !str.startsWith("http:")) {
|
||||
url = new URL("https://" + str)
|
||||
} else {
|
||||
url = new URL(str);
|
||||
}
|
||||
const blacklistedTrackingParams = [
|
||||
"fbclid",// Oh god, how I hate the fbclid. Let it burn, burn in hell!
|
||||
"gclid",
|
||||
"cmpid", "agid", "utm", "utm_source", "utm_medium",
|
||||
"campaignid","campaign","AdGroupId","AdGroup","TargetId","msclkid"]
|
||||
for (const dontLike of blacklistedTrackingParams) {
|
||||
url.searchParams.delete(dontLike.toLowerCase() )
|
||||
}
|
||||
let cleaned = url.toString();
|
||||
if (cleaned.endsWith("/") && !str.endsWith("/")) {
|
||||
// Do not add a trailing '/' if it wasn't typed originally
|
||||
cleaned = cleaned.substr(0, cleaned.length - 1)
|
||||
}
|
||||
|
||||
if (cleaned.startsWith("https://")) {
|
||||
cleaned = cleaned.substr("https://".length)
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
isValid(str: string): boolean {
|
||||
try {
|
||||
if (!str.startsWith("http://") && !str.startsWith("https://") &&
|
||||
!str.startsWith("http:")) {
|
||||
str = "https://" + str
|
||||
}
|
||||
const url = new URL(str);
|
||||
const dotIndex = url.host.indexOf(".")
|
||||
return dotIndex > 0 && url.host[url.host.length - 1 ] !== ".";
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default class ValidatedTextField {
|
||||
|
||||
public static tpList: TextFieldDef[] = [
|
||||
|
@ -356,7 +441,9 @@ export default class ValidatedTextField {
|
|||
return EmailValidator.validate(str);
|
||||
},
|
||||
str => {
|
||||
if(str === undefined){return undefined}
|
||||
if (str === undefined) {
|
||||
return undefined
|
||||
}
|
||||
if (str.startsWith("mailto:")) {
|
||||
str = str.substring("mailto:".length)
|
||||
}
|
||||
|
@ -364,40 +451,7 @@ export default class ValidatedTextField {
|
|||
},
|
||||
undefined,
|
||||
"email"),
|
||||
ValidatedTextField.tp(
|
||||
"url",
|
||||
"A url",
|
||||
(str) => {
|
||||
try {
|
||||
new URL(str);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
(str) => {
|
||||
try {
|
||||
const url = new URL(str);
|
||||
const blacklistedTrackingParams = [
|
||||
"fbclid",// Oh god, how I hate the fbclid. Let it burn, burn in hell!
|
||||
"gclid",
|
||||
"cmpid", "agid", "utm", "utm_source", "utm_medium"]
|
||||
for (const dontLike of blacklistedTrackingParams) {
|
||||
url.searchParams.delete(dontLike)
|
||||
}
|
||||
let cleaned = url.toString();
|
||||
if (cleaned.endsWith("/") && !str.endsWith("/")) {
|
||||
// Do not add a trailing '/' if it wasn't typed originally
|
||||
cleaned = cleaned.substr(0, cleaned.length - 1)
|
||||
}
|
||||
return cleaned;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
undefined,
|
||||
"url"),
|
||||
new UrlTextfieldDef(),
|
||||
ValidatedTextField.tp(
|
||||
"phone",
|
||||
"A phone number",
|
||||
|
@ -568,6 +622,14 @@ export default class ValidatedTextField {
|
|||
a => [a, a]
|
||||
).SetClass("block w-full");
|
||||
}
|
||||
if (tp.postprocess !== undefined) {
|
||||
input = new InputElementMap<string, string>(input,
|
||||
(a, b) => a === b,
|
||||
tp.postprocess,
|
||||
tp.undoPostprocess
|
||||
)
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
|
8
test.ts
8
test.ts
|
@ -1,2 +1,6 @@
|
|||
import NewNoteUi from "./UI/Popup/NewNoteUi";
|
||||
import {UIEventSource} from "./Logic/UIEventSource";
|
||||
import ValidatedTextField from "./UI/Input/ValidatedTextField";
|
||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||
|
||||
const tf = ValidatedTextField.InputForType("url")
|
||||
tf.AttachTo("maindiv")
|
||||
new VariableUiElement(tf.GetValue()).AttachTo("extradiv")
|
Loading…
Reference in a new issue