@egodesign/form 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -237,6 +237,7 @@ const myForm: EgoForm = new EgoForm({
|
|
|
237
237
|
| *customValidationMessages* | Lets you customize existing validation messages. It expects an object containing the name of the field and the custom messages inside. Refer to [Usage](#usage) to see an example. | Object or `null`.
|
|
238
238
|
| *resetOnSuccess* | This option completely resets the form and its fields. | Boolean, default `true`.
|
|
239
239
|
| *scrollOnError* | This option smoothly scrolls the page to show the first field with errors. Useful when building long forms to make sure the user sees the errors. | Boolean, default `true`.
|
|
240
|
+
| *disbleStepsTransition* | When building a multistep form, this option disables the built-in fade transition applied to each step change. If set to true it can be used together with the onStepChange event to apply your own method. | Boolean, default `false`.
|
|
240
241
|
| *debug* | On debug mode, the form won't be submitted. Intead, every step will be logged into the dev console of the browser. | Boolean, default `false`.
|
|
241
242
|
<br>
|
|
242
243
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}module.exports=class{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:F,onSuccess:g,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,preventSubmit:_,debug:L}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:L??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=F??null,this.onSuccess=g??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const x=this.form.querySelector(".form__step.--active");if(this.currentStep=x?Number(x.dataset.step):0,this.currentStepOptional=!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=L??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"json"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:"json"===this.submitDataFormat?{"Content-Type":"application/json",...this.requestHeaders}:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');(this.currentStep!==a||this.currentStepOptional)&&(this.stepChanging=!0,this.isValid=!0,setTimeout((()=>{!r||"next"!==t&&"optional"!==t||r.forEach((e=>{this.validator.validateField({field:e})||(this.isValid=!1)})),s&&o&&this.isValid?e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())}})}}):this.stepChanging=!1}),50))}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"")}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}};
|
|
1
|
+
"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}module.exports=class{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,scrollOnErrorOffset:_,preventSubmit:L,disbleStepsTransition:x,debug:D}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:D??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0,this.scrollOnErrorOffset=_||0;const C=this.form.querySelector(".form__step.--active");if(this.currentStep=C?Number(C.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=x??!1,this.stepChanging=!1,this.preventSubmit=L??!1,this.debug=D??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"formData"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&(t=e,s=this.scrollOnErrorOffset||0,t&&window.scrollTo({behavior:"smooth",top:t.getBoundingClientRect().top-document.body.getBoundingClientRect().top-s}))}var t,s}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');if(this.currentStep!==a||this.currentStepOptional)if(this.stepChanging=!0,this.isValid=!0,!r||"next"!==t&&"optional"!==t||r.forEach((e=>this.isValid=this.validator.validateField({field:e}))),s&&o&&this.isValid){const r=()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())};this.disbleStepsTransition?(s.classList.remove("--active"),r()):e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:r})}})}else this.stepChanging=!1}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().trim().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"").trim()}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(e=!1){const i=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);e||this.submitBtn.addEventListener("click",(function(e){e.preventDefault(),"function"==typeof i.onBeforeSubmit&&i.onBeforeSubmit(i),i.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),e||(this.form.querySelectorAll(".form__next-step").forEach((e=>{e.addEventListener("click",i.nextStep.bind(i))})),this.form.querySelectorAll(".form__optional-step").forEach((e=>{e.addEventListener("click",i.optionalStep.bind(i))})),this.form.querySelectorAll(".form__prev-step").forEach((e=>{e.addEventListener("click",i.prevStep.bind(i))}))),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((e=>{e.addEventListener("click",(()=>{const s=t({element:e,className:"form__field"});s&&i.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}refresh(){this.declareHandlers(!0)}};
|
|
@@ -24,14 +24,16 @@ export default class EgoForm implements EgoFormInterface {
|
|
|
24
24
|
currentStep: number;
|
|
25
25
|
currentStepOptional: boolean;
|
|
26
26
|
stepChanging: boolean;
|
|
27
|
+
disbleStepsTransition: boolean;
|
|
27
28
|
isValid: boolean;
|
|
28
29
|
hasFile: boolean;
|
|
29
30
|
resetOnSuccess: boolean;
|
|
30
31
|
resetLoaderOnSuccess: boolean;
|
|
31
32
|
scrollOnError: boolean;
|
|
33
|
+
scrollOnErrorOffset: number;
|
|
32
34
|
preventSubmit: boolean;
|
|
33
35
|
debug: boolean;
|
|
34
|
-
constructor({ element, classes, submitType, submitDataFormat, submitUrl, requestHeaders, fieldGroups, extraFields, serializerIgnoreList, customValidations, customValidationMessages, onStepChange, onValidationError, onSubmitStart, onSubmitEnd, onSuccess, onError, onBeforeSubmit, resetOnSuccess, resetLoaderOnSuccess, scrollOnError, preventSubmit, debug }: EgoFormOptions);
|
|
36
|
+
constructor({ element, classes, submitType, submitDataFormat, submitUrl, requestHeaders, fieldGroups, extraFields, serializerIgnoreList, customValidations, customValidationMessages, onStepChange, onValidationError, onSubmitStart, onSubmitEnd, onSuccess, onError, onBeforeSubmit, resetOnSuccess, resetLoaderOnSuccess, scrollOnError, scrollOnErrorOffset, preventSubmit, disbleStepsTransition, debug }: EgoFormOptions);
|
|
35
37
|
submit(): void;
|
|
36
38
|
resumeSubmit(): void;
|
|
37
39
|
submittingForm({ submitting, force }: {
|
|
@@ -74,5 +76,6 @@ export default class EgoForm implements EgoFormInterface {
|
|
|
74
76
|
togglePasswordVisibility({ btn }: {
|
|
75
77
|
btn: HTMLElement;
|
|
76
78
|
}): void;
|
|
77
|
-
declareHandlers(): void;
|
|
79
|
+
declareHandlers(isRefresh?: boolean): void;
|
|
80
|
+
refresh(): void;
|
|
78
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}class a{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:F,onSuccess:g,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,preventSubmit:_,debug:L}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:L??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=F??null,this.onSuccess=g??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const x=this.form.querySelector(".form__step.--active");if(this.currentStep=x?Number(x.dataset.step):0,this.currentStepOptional=!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=L??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"json"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:"json"===this.submitDataFormat?{"Content-Type":"application/json",...this.requestHeaders}:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');(this.currentStep!==a||this.currentStepOptional)&&(this.stepChanging=!0,this.isValid=!0,setTimeout((()=>{!r||"next"!==t&&"optional"!==t||r.forEach((e=>{this.validator.validateField({field:e})||(this.isValid=!1)})),s&&o&&this.isValid?e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())}})}}):this.stepChanging=!1}),50))}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"")}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}}export{a as default};
|
|
1
|
+
const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}class a{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,scrollOnErrorOffset:_,preventSubmit:L,disbleStepsTransition:x,debug:D}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:D??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0,this.scrollOnErrorOffset=_||0;const C=this.form.querySelector(".form__step.--active");if(this.currentStep=C?Number(C.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=x??!1,this.stepChanging=!1,this.preventSubmit=L??!1,this.debug=D??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"formData"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&(t=e,s=this.scrollOnErrorOffset||0,t&&window.scrollTo({behavior:"smooth",top:t.getBoundingClientRect().top-document.body.getBoundingClientRect().top-s}))}var t,s}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');if(this.currentStep!==a||this.currentStepOptional)if(this.stepChanging=!0,this.isValid=!0,!r||"next"!==t&&"optional"!==t||r.forEach((e=>this.isValid=this.validator.validateField({field:e}))),s&&o&&this.isValid){const r=()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())};this.disbleStepsTransition?(s.classList.remove("--active"),r()):e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:r})}})}else this.stepChanging=!1}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().trim().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"").trim()}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(e=!1){const i=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);e||this.submitBtn.addEventListener("click",(function(e){e.preventDefault(),"function"==typeof i.onBeforeSubmit&&i.onBeforeSubmit(i),i.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),e||(this.form.querySelectorAll(".form__next-step").forEach((e=>{e.addEventListener("click",i.nextStep.bind(i))})),this.form.querySelectorAll(".form__optional-step").forEach((e=>{e.addEventListener("click",i.optionalStep.bind(i))})),this.form.querySelectorAll(".form__prev-step").forEach((e=>{e.addEventListener("click",i.prevStep.bind(i))}))),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((e=>{e.addEventListener("click",(()=>{const s=t({element:e,className:"form__field"});s&&i.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}refresh(){this.declareHandlers(!0)}}export{a as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).egodesign=e.egodesign||{},e.egodesign.form=t())}(this,(function(){"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}return class{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,preventSubmit:_,debug:L}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:L??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const x=this.form.querySelector(".form__step.--active");if(this.currentStep=x?Number(x.dataset.step):0,this.currentStepOptional=!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=L??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"json"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:"json"===this.submitDataFormat?{"Content-Type":"application/json",...this.requestHeaders}:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');(this.currentStep!==a||this.currentStepOptional)&&(this.stepChanging=!0,this.isValid=!0,setTimeout((()=>{!r||"next"!==t&&"optional"!==t||r.forEach((e=>{this.validator.validateField({field:e})||(this.isValid=!1)})),s&&o&&this.isValid?e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())}})}}):this.stepChanging=!1}),50))}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"")}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}}}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).egodesign=e.egodesign||{},e.egodesign.form=t())}(this,(function(){"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}return class{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,scrollOnErrorOffset:_,preventSubmit:L,disbleStepsTransition:x,debug:D}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=l||{},this.actionUrl=this.form.getAttribute("action")||o||null,this.submitMethod=this.form.getAttribute("method")||"POST",this.submitBtn=this.form.querySelector('button[type="submit"]')||null,this.classes={requiredField:"--required",requiredIfFilledField:"--required-if-filled",fieldHasError:"--has-error",hiddenErrorMessage:"--hidden",formSubmittingState:"--submitting",buttonSubmittingState:"--loading",clearFieldError:"--clear-error",validateOnBlur:"--validate-onblur",validateOnInput:"--validate-oninput",...t},this.isValid=!0,this.validator=new r({customValidations:c||{},classes:this.classes,customValidationMessages:m||null,debug:D??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0,this.scrollOnErrorOffset=_||0;const C=this.form.querySelector(".form__step.--active");if(this.currentStep=C?Number(C.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=x??!1,this.stepChanging=!1,this.preventSubmit=L??!1,this.debug=D??!1,this.declareHandlers(),!this.actionUrl||""===this.actionUrl)throw new Error("The form doesn't have an action attribute or submitUrl wasn't provided.");this.debug&&i("initialized!")}submit(){this.preventSubmit||this.resumeSubmit()}resumeSubmit(){this.debug&&i(`submitting using ${this.submitType}!`),this.submittingForm({submitting:!0}),this.isValid=!0;const e=[];if(this.form.querySelectorAll(".form__field").forEach((t=>{if(!this.validator.validateField({field:t})){const i=t.querySelector(".form__control");i&&e.push(i.name),this.isValid=!1}})),this.isValid)if(this.debug)i("the form was submitted!"),i(JSON.parse(this.serializeData({returnFormData:!1})),"data"),setTimeout((()=>{this.submittingForm({submitting:!1,force:!0})}),1e3);else if("fetch"==this.submitType&&this.actionUrl){const e=this.serializeData({returnFormData:"formData"===this.submitDataFormat});fetch(this.actionUrl,{method:this.submitMethod,headers:{...this.requestHeaders},body:e}).then((e=>{200===e.status||201===e.status?(this.resetOnSuccess&&this.reset(),"function"==typeof this.onSuccess&&this.onSuccess(e)):"function"==typeof this.onError&&this.onError(e)})).catch((e=>{"function"==typeof this.onError&&this.onError(e)})).finally((()=>{this.submittingForm({submitting:!1})}))}else{if("fetch"==this.submitType&&!this.actionUrl)throw new Error("Missing submit URL: When using 'fetch' submitType, specify either the form's 'action' or the 'submitUrl' option.");this.form.submit()}else if(this.submittingForm({submitting:!1,force:!0}),"function"==typeof this.onValidationError&&this.onValidationError(e,this),this.debug&&i(`this fields have failed validation: ${e.toString().replace(/,/g,", ")}.`),this.scrollOnError){const e=this.form.querySelector(`.form__field.${this.classes.fieldHasError}`);e&&!(({element:e})=>{const t=e.getBoundingClientRect();return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)})({element:e})&&(t=e,s=this.scrollOnErrorOffset||0,t&&window.scrollTo({behavior:"smooth",top:t.getBoundingClientRect().top-document.body.getBoundingClientRect().top-s}))}var t,s}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');if(this.currentStep!==a||this.currentStepOptional)if(this.stepChanging=!0,this.isValid=!0,!r||"next"!==t&&"optional"!==t||r.forEach((e=>this.isValid=this.validator.validateField({field:e}))),s&&o&&this.isValid){const r=()=>{o.classList.add("--active"),this.stepChanging=!1,this.currentStepOptional="optional"===t,this.currentStep=parseInt(a),"function"==typeof this.onStepChange&&this.onStepChange(i.toString(),a.toString())};this.disbleStepsTransition?(s.classList.remove("--active"),r()):e({element:s,enter:!1,time:200,displayType:"flex",callback:()=>{s.classList.remove("--active"),e({element:o,enter:!0,time:200,displayType:"flex",callback:r})}})}else this.stepChanging=!1}}nextStep(){this.changeStep({step:"next"})}optionalStep(){this.changeStep({step:"optional"})}prevStep(){this.changeStep({step:"prev"})}isControlFilled({control:e}){let t=e.parentElement;t&&(""!==e.value?t.classList.add("--filled"):t.classList.remove("--filled"))}filterNumber({value:e,ignoreList:t=[]}){const i=t.join(""),s=new RegExp("[^"+i+"0-9]","g");return e.toString().replace(s,"")}filterFormattedQuantity({num:e,thousands:t=".",decimals:i=",",decimalSteps:s}){const r=i?e.toString().trim().split(i):[e.toString()],a=new RegExp(/\B(?=(\d{3})+(?!\d))/g),o=r[0].replace(a,t);let l="";return l=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,l}filterMoneyAmount({num:e,currency:t="$",thousands:i=".",decimals:s=",",decimalSteps:r}){if(!e||e==t)return"";let a=this.filterNumber({value:e,ignoreList:[s||""]});return a=this.filterFormattedQuantity({num:a,thousands:i,decimals:s,decimalSteps:r}),`${t} ${a}`}filterPhoneNumber({number:e}){let t=new RegExp(/[^\d+\-() ]*/g);return e.replace(t,"").trim()}togglePasswordVisibility({btn:e}){this.debug&&i("Password visibility toggled!");const t=e?.parentElement?.querySelector(".form__control");if(t){const i="password"===t.getAttribute("type")?"text":"password";t.setAttribute("type",i),e.classList.toggle("--hide")}}declareHandlers(e=!1){const i=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);e||this.submitBtn.addEventListener("click",(function(e){e.preventDefault(),"function"==typeof i.onBeforeSubmit&&i.onBeforeSubmit(i),i.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),e||(this.form.querySelectorAll(".form__next-step").forEach((e=>{e.addEventListener("click",i.nextStep.bind(i))})),this.form.querySelectorAll(".form__optional-step").forEach((e=>{e.addEventListener("click",i.optionalStep.bind(i))})),this.form.querySelectorAll(".form__prev-step").forEach((e=>{e.addEventListener("click",i.prevStep.bind(i))}))),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((e=>{e.addEventListener("click",(()=>{const s=t({element:e,className:"form__field"});s&&i.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}refresh(){this.declareHandlers(!0)}}}));
|
|
@@ -13,3 +13,4 @@ export declare const isInViewport: ({ element }: {
|
|
|
13
13
|
element: HTMLElement;
|
|
14
14
|
}) => boolean;
|
|
15
15
|
export declare function showLog(msg: string, type?: 'log' | 'data'): void;
|
|
16
|
+
export declare function scrollIntoViewWithOffset(element: HTMLElement | null, offset: number): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@egodesign/form",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "JS/TS Form component",
|
|
5
6
|
"module": "dist/js/egodesign.form.esm.min.js",
|
|
6
7
|
"browser": "dist/js/egodesign.form.umd.min.js",
|
|
@@ -9,7 +10,7 @@
|
|
|
9
10
|
"scripts": {
|
|
10
11
|
"build": "rollup -c",
|
|
11
12
|
"watch": "rollup -c -w",
|
|
12
|
-
"test": "
|
|
13
|
+
"test": "vitest"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
@@ -30,13 +31,13 @@
|
|
|
30
31
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
|
31
32
|
"@rollup/plugin-terser": "^0.4.4",
|
|
32
33
|
"@rollup/plugin-typescript": "^12.1.2",
|
|
34
|
+
"@types/node": "^22.13.9",
|
|
33
35
|
"esm": "^3.2.25",
|
|
34
|
-
"
|
|
35
|
-
"jest-environment-jsdom": "^29.5.0",
|
|
36
|
+
"jsdom": "^26.0.0",
|
|
36
37
|
"rollup": "^4.34.8",
|
|
37
38
|
"sass": "^1.60.0",
|
|
38
39
|
"tslib": "^2.8.1",
|
|
39
|
-
"
|
|
40
|
+
"vitest": "^3.0.7"
|
|
40
41
|
},
|
|
41
42
|
"files": [
|
|
42
43
|
"dist"
|