diff --git a/radicale/web/internal_data/js/scenes/CreateEditCollectionScene.js b/radicale/web/internal_data/js/scenes/CreateEditCollectionScene.js index 3b6c280b..b780cca7 100644 --- a/radicale/web/internal_data/js/scenes/CreateEditCollectionScene.js +++ b/radicale/web/internal_data/js/scenes/CreateEditCollectionScene.js @@ -22,7 +22,9 @@ import { create_collection, edit_collection } from "../api/api.js"; import { COLOR_RE } from "../constants.js"; import { Collection, CollectionType } from "../models/collection.js"; -import { cleanHREFinput, isValidHREF, onCleanHREFinput, random_hex, random_uuid } from "../utils/misc.js"; +import { ErrorHandler } from "../utils/error.js"; +import { FormValidator, validate_color, validate_href } from "../utils/form_validator.js"; +import { cleanHREFinput, onCleanHREFinput, random_hex, random_uuid } from "../utils/misc.js"; import { LoadingScene } from "./LoadingScene.js"; import { Scene, pop_scene, push_scene, scene_stack } from "./scene_manager.js"; @@ -55,9 +57,16 @@ export class CreateEditCollectionScene { /** @type {?number} */ let scene_index = null; /** @type {?XMLHttpRequest} */ let create_edit_req = null; - let error = ""; /** @type {?HTMLSelectElement} */ let saved_type_form = null; + let errorHandler = new ErrorHandler(error_form); + let validator = new FormValidator(errorHandler); + + if (!edit) { + validator.addValidator(href_form, validate_href(href_form, "HREF")); + } + validator.addValidator(color_form, validate_color(color_form, "Color")); + let href = edit ? collection.href : collection.href + random_uuid() + "/"; let displayname = edit ? collection.displayname : ""; let description = edit ? collection.description : ""; @@ -87,10 +96,6 @@ export class CreateEditCollectionScene { if (!edit) { cleanHREFinput(href_form); let newhreftxtvalue = href_form.value.trim().toLowerCase(); - if (!isValidHREF(newhreftxtvalue)) { - alert("You must enter a valid HREF"); - return false; - } href = collection.href + newhreftxtvalue + "/"; } displayname = displayname_form.value; @@ -110,29 +115,19 @@ export class CreateEditCollectionScene { source_form.value = source; type_form.value = type; color_form.value = color; - if (error) { - error_form.textContent = "Error: " + error; - error_form.classList.remove("hidden"); - } - error_form.classList.add("hidden"); onTypeChange(null); type_form.addEventListener("change", onTypeChange); } function onsubmit() { try { - if (!read_form()) { + if (!validator.validate()) { return false; } + read_form(); let sane_color = color.trim(); if (sane_color) { - let color_match = COLOR_RE.exec(sane_color); - if (!color_match) { - error = "Invalid color"; - fill_form(); - return false; - } - sane_color = color_match[1]; + sane_color = COLOR_RE.exec(sane_color)[1]; } let loading_scene = new LoadingScene(); push_scene(loading_scene, false); @@ -143,7 +138,7 @@ export class CreateEditCollectionScene { } create_edit_req = null; if (error1) { - error = error1; + errorHandler.setError(error1); pop_scene(scene_index); } else { pop_scene(scene_index - 1); @@ -197,12 +192,7 @@ export class CreateEditCollectionScene { fill_form(); submit_btn.onclick = onsubmit; cancel_btn.onclick = oncancel; - if (error) { - error_form.textContent = "Error: " + error; - error_form.classList.remove("hidden"); - } else { - error_form.classList.add("hidden"); - } + validator.validate(); }; this.hide = function () { read_form(); diff --git a/radicale/web/internal_data/js/utils/form_validator.js b/radicale/web/internal_data/js/utils/form_validator.js index 96645296..252dbba6 100644 --- a/radicale/web/internal_data/js/utils/form_validator.js +++ b/radicale/web/internal_data/js/utils/form_validator.js @@ -16,7 +16,9 @@ * along with this program. If not, see . */ +import { COLOR_RE } from "../constants.js"; import { ErrorHandler } from "./error.js"; +import { isValidHREF } from "./misc.js"; /** * Manages form validation by running validation functions on input fields. @@ -74,7 +76,44 @@ export function validate_non_empty(input, field_name) { return field_name + " is empty"; }; } +/** + * Validates that the input is a valid HREF. + * @param {HTMLInputElement} input + * @param {string} field_name + * @returns {function(): ?string} + */ +export function validate_href(input, field_name) { + return () => { + let value = input.value.trim(); + if (!value) { + return field_name + " is empty"; + } + if (value.startsWith("/")) { + return field_name + " cannot start with /"; + } + if (!isValidHREF(value)) { + return field_name + " is invalid"; + } + return null; + }; +} - - +/** + * Validates that the input is a valid color. + * @param {HTMLInputElement} input + * @param {string} field_name + * @returns {function(): ?string} + */ +export function validate_color(input, field_name) { + return () => { + let value = input.value.trim(); + if (!value) { + return null; + } + if (!COLOR_RE.exec(value)) { + return field_name + " is invalid"; + } + return null; + }; +}