diff --git a/app/static/js/date_utils.js b/app/static/js/date_utils.js index 4c24624afd..d22487d323 100644 --- a/app/static/js/date_utils.js +++ b/app/static/js/date_utils.js @@ -323,45 +323,94 @@ class Duration { class ScoDocDateTimePicker extends HTMLElement { constructor() { super(); - // Initialisation du shadow DOM pour l'encapsulation du style et du comportement. + // Définir si le champ est requis + this.required = this.hasAttribute("required"); + + // Initialiser le shadow DOM const shadow = this.attachShadow({ mode: "open" }); - // Création de l'input pour la date. + // Créer l'input pour la date const dateInput = document.createElement("input"); dateInput.type = "date"; dateInput.id = "date"; - // Création de l'input pour l'heure. + // Créer l'input pour l'heure const timeInput = document.createElement("input"); timeInput.type = "time"; timeInput.id = "time"; - // Ajout des inputs date et heure dans le shadow DOM. + // Ajouter les inputs dans le shadow DOM shadow.appendChild(dateInput); shadow.appendChild(timeInput); - // Ajout de gestionnaires d'événements pour mettre à jour la valeur lorsque les inputs changent. + // Gestionnaires d'événements pour la mise à jour de la valeur dateInput.addEventListener("change", () => this.updateValue()); timeInput.addEventListener("change", () => this.updateValue()); - // Style CSS pour les inputs, ici pour les afficher côte à côte. + // Style CSS pour les inputs const style = document.createElement("style"); style.textContent = ` - input { + input { display: inline-block; - } + } + input:invalid { + border: 1px solid red; + } `; - // Ajout du style dans le shadow DOM. + // Ajouter le style au shadow DOM shadow.appendChild(style); } - // Méthode pour mettre à jour la valeur interne basée sur les inputs de date et d'heure. + connectedCallback() { + // Récupérer l'attribut 'name' + this.name = this.getAttribute("name"); + + // Créer un input caché pour la valeur datetime + this.hiddenInput = document.createElement("input"); + this.hiddenInput.type = "hidden"; + this.hiddenInput.name = this.name; + this.appendChild(this.hiddenInput); + + // Gérer la soumission du formulaire + this.closest("form")?.addEventListener("submit", (e) => { + if (!this.validate()) { + e.preventDefault(); // Empêcher la soumission si non valide + this.dispatchEvent( + new Event("invalid", { bubbles: true, cancelable: true }) + ); + } else { + // Mettre à jour la valeur de l'input caché avant la soumission + this.hiddenInput.value = this.isValid() + ? this.valueAsDate.toIsoUtcString() + : ""; + } + }); + } + + // Vérifier si la valeur forme une date valide + isValid() { + return !Number.isNaN(this.valueAsDate.getTime()); + } + + // Valider l'élément + validate() { + if (this.required && !this.isValid()) { + return false; + } + return true; + } + + // Mettre à jour la valeur interne updateValue() { const dateInput = this.shadowRoot.querySelector("#date"); const timeInput = this.shadowRoot.querySelector("#time"); - // Formatage de la valeur en format datetime ISO (YYYY-MM-DDTHH:MM). this._value = `${dateInput.value}T${timeInput.value}`; + this.dispatchEvent(new Event("change", { bubbles: true })); + + // Appliquer le style 'invalid' si nécessaire + dateInput.classList.toggle("invalid", this.required && !this.isValid()); + timeInput.classList.toggle("invalid", this.required && !this.isValid()); } // Getter pour obtenir la valeur actuelle. @@ -371,8 +420,13 @@ class ScoDocDateTimePicker extends HTMLElement { // Setter pour définir la valeur. Sépare la valeur en date et heure et les définit individuellement. set value(val) { - const [date, time] = val.split("T"); + let [date, time] = val.split("T"); this.shadowRoot.querySelector("#date").value = date; + + if ((time.match(/0/g) || []).length > 1) { + time = time.slice(0, time.indexOf(":") + 3); + } + this.shadowRoot.querySelector("#time").value = time; this._value = val; }