/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */
import $ from"jquery";import{DateTime}from"luxon";import Md5 from"@typo3/backend/hashing/md5.js";import Modal from"@typo3/backend/modal.js";import Severity from"@typo3/backend/severity.js";import Utility from"@typo3/backend/utility.js";import RegularEvent from"@typo3/core/event/regular-event.js";import DomHelper from"@typo3/backend/utility/dom-helper.js";import{selector}from"@typo3/core/literals.js";import SubmitInterceptor from"@typo3/backend/form/submit-interceptor.js";import{FormEngineReview}from"@typo3/backend/form-engine-review.js";let formEngineInstance,validationSuspended=!1;const customEvaluations=new Map;class FormEngineValidation{static{this.rulesSelector="[data-formengine-validation-rules]"}static{this.inputSelector="[data-formengine-input-params]"}static{this.markerSelector=".t3js-formengine-validation-marker"}static{this.labelSelector=".t3js-formengine-label"}static{this.errorClass="has-error"}static{this.validationErrorClass="has-validation-error"}static{this.passwordDummy="********"}static initialize(e){formEngineInstance=e,formEngineInstance.formElement.querySelectorAll("."+FormEngineValidation.errorClass).forEach(t=>t.classList.remove(FormEngineValidation.errorClass)),FormEngineValidation.initializeInputFields(),new FormEngineReview(formEngineInstance.formElement),new RegularEvent("change",(t,n)=>{FormEngineValidation.validateField(n),FormEngineValidation.markFieldAsChanged(n)}).delegateTo(formEngineInstance.formElement,FormEngineValidation.rulesSelector),FormEngineValidation.registerSubmitCallback(),FormEngineValidation.validate()}static initializeInputFields(){formEngineInstance.formElement.querySelectorAll(FormEngineValidation.inputSelector).forEach(e=>{if("formengineInputInitialized"in e.dataset)return;const n=JSON.parse(e.dataset.formengineInputParams).field,a=formEngineInstance.formElement.querySelector(selector`[name="${n}"]`);a.dataset.config=e.dataset.formengineInputParams,FormEngineValidation.initializeInputField(n)})}static initializeInputField(e){const t=formEngineInstance.formElement.querySelector(selector`[name="${e}"]`),n=formEngineInstance.formElement.querySelector(selector`[data-formengine-input-name="${e}"]`);if(t.dataset.config!==void 0){const a=JSON.parse(t.dataset.config),i=FormEngineValidation.formatByEvals(a,t.value);i.length&&(n.value=i)}new RegularEvent("change",()=>{FormEngineValidation.updateInputField(n.dataset.formengineInputName)}).bindTo(n),n.dataset.formengineInputInitialized="true"}static registerCustomEvaluation(e,t){customEvaluations.has(e)||customEvaluations.set(e,t)}static formatByEvals(e,t){if(e.evalList!==void 0){const n=Utility.trimExplode(",",e.evalList);for(const a of n)t=FormEngineValidation.formatValue(a,t)}return t}static formatValue(e,t){switch(e){case"date":case"datetime":case"time":case"timesec":if(t==="")return"";const n=DateTime.fromISO(String(t),{zone:"utc"});if(!n.isValid)throw new Error("Invalid ISO8601 DateTime string: "+t);return n.toISO({suppressMilliseconds:!0});case"password":return t?FormEngineValidation.passwordDummy:"";default:return t.toString()}}static updateInputField(e){const t=formEngineInstance.formElement.querySelector(selector`[name="${e}"]`),n=formEngineInstance.formElement.querySelector(selector`[data-formengine-input-name="${e}"]`);if(t.dataset.config!==void 0){const a=JSON.parse(t.dataset.config),i=FormEngineValidation.processByEvals(a,n.value),l=FormEngineValidation.formatByEvals(a,i);t.value!==i&&(t.disabled&&t.dataset.enableOnModification&&(t.disabled=!1),t.value=i,t.dispatchEvent(new Event("change"))),n.value!==l&&(n.value=l)}}static validateField(e,t){if(e instanceof $&&(console.warn("Passing a jQuery element to FormEngineValidation.validateField() is deprecated and will be removed in TYPO3 v14."),console.trace(),e=e.get(0)),!(e instanceof HTMLElement)||(t=t||e.value||"",typeof e.dataset.formengineValidationRules>"u"))return t;const n=JSON.parse(e.dataset.formengineValidationRules);let a=!1,i=0;const l=t;let s,o,m;Array.isArray(t)||(t=t.trimStart());for(const r of n){if(a)break;switch(r.type){case"required":t===""&&(a=!0,e.classList.add(FormEngineValidation.errorClass),e.closest(FormEngineValidation.markerSelector)?.querySelector(FormEngineValidation.labelSelector)?.classList.add(FormEngineValidation.errorClass));break;case"range":if(t!==""){if((r.minItems||r.maxItems)&&(s=formEngineInstance.formElement.querySelector(selector`[name="${e.dataset.relatedfieldname}"]`),s!==null?i=Utility.trimExplode(",",s.value).length:i=parseInt(e.value,10),r.minItems!==void 0&&(o=r.minItems*1,!isNaN(o)&&i<o&&(a=!0)),r.maxItems!==void 0&&(m=r.maxItems*1,!isNaN(m)&&i>m&&(a=!0))),r.lower!==void 0)if(e.dataset.inputType==="datetimepicker"){const c=DateTime.fromISO(t,{zone:"utc"}),u=DateTime.fromISO(r.lower,{zone:"utc"});(!c.isValid||c<u.minus(u.second*1e3))&&(a=!0)}else{const c=r.lower*1;!isNaN(c)&&parseInt(t,10)<c&&(a=!0)}if(r.upper!==void 0)if(e.dataset.inputType==="datetimepicker"){const c=DateTime.fromISO(t,{zone:"utc"}),u=DateTime.fromISO(r.upper,{zone:"utc"});(!c.isValid||c>u.plus((59-u.second)*1e3))&&(a=!0)}else{const c=r.upper*1;!isNaN(c)&&parseInt(t,10)>c&&(a=!0)}}break;case"select":case"category":(r.minItems||r.maxItems)&&(s=formEngineInstance.formElement.querySelector(selector`[name="${e.dataset.relatedfieldname}"]`),s!==null?i=Utility.trimExplode(",",s.value).length:e instanceof HTMLSelectElement?i=e.querySelectorAll("option:checked").length:i=e.querySelectorAll("input[value]:checked").length,r.minItems!==void 0&&(o=r.minItems*1,!isNaN(o)&&i<o&&(a=!0)),r.maxItems!==void 0&&(m=r.maxItems*1,!isNaN(m)&&i>m&&(a=!0)));break;case"group":case"folder":(r.minItems||r.maxItems)&&(i=Utility.trimExplode(",",e.value).length,r.minItems!==void 0&&(o=r.minItems*1,!isNaN(o)&&i<o&&(a=!0)),r.maxItems!==void 0&&(m=r.maxItems*1,!isNaN(m)&&i>m&&(a=!0)));break;case"inline":(r.minItems||r.maxItems)&&(i=Utility.trimExplode(",",e.value).length,r.minItems!==void 0&&(o=r.minItems*1,!isNaN(o)&&i<o&&(a=!0)),r.maxItems!==void 0&&(m=r.maxItems*1,!isNaN(m)&&i>m&&(a=!0)));break;case"min":(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&e.value.length>0&&e.value.length<e.minLength&&(a=!0);break;case"null":break;default:break}}const d=!a;return e.classList.toggle(FormEngineValidation.errorClass,!d),e.setAttribute("aria-invalid",a.toString()),e.closest(FormEngineValidation.markerSelector)?.querySelector(FormEngineValidation.labelSelector)?.classList.toggle(FormEngineValidation.errorClass,!d),FormEngineValidation.markParentTab(e,d),formEngineInstance.formElement.dispatchEvent(new CustomEvent("t3-formengine-postfieldvalidation",{detail:{field:e,isValid:d},cancelable:!1,bubbles:!0})),l}static processByEvals(e,t){if(e.evalList!==void 0){const n=Utility.trimExplode(",",e.evalList);for(const a of n)t=FormEngineValidation.processValue(a,t,e)}return t}static processValue(e,t,n){let a="",i="",l=0,s=t;switch(e){case"alpha":case"num":case"alphanum":case"alphanum_x":for(a="",l=0;l<t.length;l++){const o=t.substr(l,1);let m=o==="_"||o==="-",d=o>="a"&&o<="z"||o>="A"&&o<="Z",r=o>="0"&&o<="9";switch(e){case"alphanum":m=!1;break;case"alpha":r=!1,m=!1;break;case"num":d=!1,m=!1;break;default:break}(d||r||m)&&(a+=o)}a!==t&&(s=a);break;case"is_in":if(n.is_in){i=""+t,n.is_in=n.is_in.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&");const o=new RegExp("[^"+n.is_in+"]+","g");a=i.replace(o,"")}else a=i;s=a;break;case"nospace":s=(""+t).replace(/ /g,"");break;case"md5":t!==""&&(s=Md5.hash(t));break;case"upper":s=t.toUpperCase();break;case"lower":s=t.toLowerCase();break;case"integer":t!==""&&(s=FormEngineValidation.parseInt(t).toString());break;case"decimal":t!==""&&(s=FormEngineValidation.parseDouble(t));break;case"trim":s=String(t).trim();break;case"time":case"timesec":t!==""&&(s=DateTime.fromISO(t,{zone:"utc"}).set({year:1970,month:1,day:1}).toISO({suppressMilliseconds:!0}));break;case"year":if(t!==""){let o=parseInt(t,10);isNaN(o)&&(o=new Date().getUTCFullYear()),s=o.toString(10)}break;case"null":break;case"password":break;default:customEvaluations.has(e)?s=customEvaluations.get(e).call(null,t):typeof TBE_EDITOR=="object"&&TBE_EDITOR.customEvalFunctions!==void 0&&typeof TBE_EDITOR.customEvalFunctions[e]=="function"&&(s=TBE_EDITOR.customEvalFunctions[e](t))}return s}static validate(e){(typeof e>"u"||e instanceof Document)&&formEngineInstance.formElement.querySelectorAll(FormEngineValidation.markerSelector+", .t3js-tabmenu-item").forEach(n=>{n.classList.remove(FormEngineValidation.validationErrorClass)});const t=e||document;for(const n of t.querySelectorAll(FormEngineValidation.rulesSelector))if(n.closest(".t3js-flex-section-deleted, .t3js-inline-record-deleted, .t3js-file-reference-deleted")===null){let a=!1;const i=n.value,l=FormEngineValidation.validateField(n,i);if(Array.isArray(l)&&Array.isArray(i)){if(l.length!==i.length)a=!0;else for(let s=0;s<l.length;s++)if(l[s]!==i[s]){a=!0;break}}else l.length&&i!==l&&(a=!0);a&&(n.disabled&&n.dataset.enableOnModification&&(n.disabled=!1),n.value=l)}}static markFieldAsChanged(e){if(e instanceof $&&(console.warn("Passing a jQuery element to FormEngineValidation.markFieldAsChanged() is deprecated and will be removed in TYPO3 v14."),console.trace(),e=e.get(0)),!(e instanceof HTMLElement))return;e.classList.add("has-change");const t=e.closest(".t3js-formengine-palette-field")?.querySelector(".t3js-formengine-label");t!==null&&t.classList.add("has-change")}static parseInt(e){const t=""+e;if(!e)return 0;const n=parseInt(t,10);return isNaN(n)?0:n}static parseDouble(e,t=2){let n=""+e;n=n.replace(/[^0-9,.-]/g,"");const a=n.startsWith("-");n=n.replace(/-/g,""),n=n.replace(/,/g,"."),n.indexOf(".")===-1&&(n+=".0");const i=n.split("."),l=i.pop();let s=+(i.join("")+"."+l);return a&&(s*=-1),n=s.toFixed(t),n}static pol(foreign,value){return eval((foreign=="-"?"-":"")+value)}static markParentTab(e,t){DomHelper.parents(e,".tab-pane").forEach(a=>{t&&(t=a.querySelector(".has-error")===null);const i=a.id;formEngineInstance.formElement.querySelector('[data-bs-target="#'+i+'"]').closest(".t3js-tabmenu-item").classList.toggle(FormEngineValidation.validationErrorClass,!t)})}static suspend(){validationSuspended=!0}static resume(){validationSuspended=!1}static isValid(){return document.querySelector("."+FormEngineValidation.errorClass)===null}static showErrorModal(){const e=Modal.confirm(TYPO3.lang.alert||"Alert",TYPO3.lang["FormEngine.fieldsMissing"],Severity.error,[{text:TYPO3.lang["button.ok"]||"OK",active:!0,btnClass:"btn-default",name:"ok"}]);e.addEventListener("button.clicked",()=>e.hideModal())}static registerSubmitCallback(){new SubmitInterceptor(formEngineInstance.formElement).addPreSubmitCallback(()=>validationSuspended||FormEngineValidation.isValid()?!0:(FormEngineValidation.showErrorModal(),!1))}}export{FormEngineValidation as default};
