@egodesign/form 1.8.0 → 1.9.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
@@ -66,7 +66,7 @@ const myForm = new EgoForm({
66
66
  customValidations: {
67
67
  test: [{
68
68
  name: 'isValid',
69
- condition: (value) => value === 'testing',
69
+ condition: (value, fieldName) => value === 'testing',
70
70
  message: 'This field value should be "testing".'
71
71
  }]
72
72
  },
@@ -77,9 +77,10 @@ const myForm = new EgoForm({
77
77
  }
78
78
  },
79
79
  onStepChange: (previous, next) => console.log(current, next),
80
- onBeforeSubmit: () => console.log('Before submit'),
80
+ onBeforeValidation: instance => instance.resumeValidation(),
81
81
  onValidationError: fields => console.log(fields),
82
82
  onSubmitStart: () => console.log('Submit start'),
83
+ onBeforeSubmission: instance => instance.resumeSubmission(),
83
84
  onSubmitEnd: () => console.log('Submit end'),
84
85
  onSuccess: resp => console.log('Success', resp),
85
86
  onError: err => console.log('Error', err)
@@ -124,7 +125,7 @@ const myForm: EgoForm = new EgoForm({
124
125
  customValidations: {
125
126
  test: [{
126
127
  name: 'isValid',
127
- condition: (value: string | number) => value === 'testing',
128
+ condition: (value: string | number, fieldName: string) => value === 'testing',
128
129
  message: 'This field value should be "testing".'
129
130
  }]
130
131
  },
@@ -134,14 +135,14 @@ const myForm: EgoForm = new EgoForm({
134
135
  "invalid": "message",
135
136
  }
136
137
  },
137
- onValidationError: (fields: string[], instance: EgoForm) => {
138
- console.log(instance, fields);
139
- },
140
- onStepChange: (prev: string, next: string) => console.log(prev, next),
141
- onSubmitStart: () => console.log('Submit start'),
142
- onSubmitEnd: () => console.log('Submit end'),
143
- onSuccess: (resp: Response) => console.log('Success', resp),
144
- onError: (err: Error) => console.log('Error', err)
138
+ onStepChange: (prev: string, next: string) => console.log(prev, next),
139
+ onBeforeValidation: (instance: EgoForm) => instance.resumeValidation(),
140
+ onValidationError: (fields: string[], instance: EgoForm) => console.log(instance, fields),
141
+ onSubmitStart: () => console.log('Submit start'),
142
+ onBeforeSubmission: (instance: EgoForm) => instance.resumeSubmission(),
143
+ onSubmitEnd: () => console.log('Submit end'),
144
+ onSuccess: (resp: Response) => console.log('Success', resp),
145
+ onError: (err: Error) => console.log('Error', err)
145
146
  });
146
147
  ```
147
148
  </details>
@@ -233,11 +234,13 @@ const myForm: EgoForm = new EgoForm({
233
234
  | *fieldGroups* | Group fields as nestes objects inside the body of the request. Should recieve an object containing key-value pairs, where the key is the name of the group and the value an array listing the field names. | Object or `null`.
234
235
  | *extraFields* | Add extra fields to the request body. Should recieve an array containing objects with the name and value of the field. This fields are **NOT** validated. | Array of objects or empty array.
235
236
  | *classes* | Customize some classes to match your own. Should recieve an object containig the replaced classnames. See [customizable classes] | Object or `null`.
236
- | *customValidations* | Define your own validations. Should recieve an object containig key-value pairs, where the key is the name of the custom `data-type`, and the value an array of validations defining a condition to be passed and a message in case it's not. | Object or `null`.
237
+ | *customValidations* | Define your own validations. Should recieve an object containig key-value pairs, where the key is the name of the custom `data-type`, and the value an array of validations defining a condition function to be passed and a message in case it's not. | Object or `null`.
237
238
  | *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
239
  | *resetOnSuccess* | This option completely resets the form and its fields. | Boolean, default `true`.
239
240
  | *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
241
  | *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`.
242
+ | *preventValidation* | Prevents the form from being validated. Useful in combination with onBeforeValidation event and the `resumeValidation()` method. | Boolean, default `false`.
243
+ | *preventSubmission* | After validation passed, it prevents the form from being submitted. Useful in combination with onBeforeSubmission event and the `resumeSubmission()` method. | Boolean, default `false`.
241
244
  | *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`.
242
245
  <br>
243
246
 
@@ -246,8 +249,9 @@ const myForm: EgoForm = new EgoForm({
246
249
  | --- | ----------- | ----------- |
247
250
  | *onStepChange* | Event triggered every time there's a step change. Only available for stepped forms. It returns the previous and the next steps. | An anonymous function or `null`.
248
251
  | *onValidationError* | Event triggered when there's any validation error. The callback function receives an array containing the names of invalid fields and a reference to the instance itself. | An anonymous function or `null`.
249
- | *onBeforeSubmit* | Event triggered before the submit starts. The callback function receives a reference to the instance itself | An anonymous function or `null`.
252
+ | *onBeforeValidation* | Event triggered before the validation starts. The callback function receives a reference to the instance itself | An anonymous function or `null`.
250
253
  | *onSubmitStart* | Event triggered when the submit starts. | An anonymous function or `null`.
254
+ | *onBeforeSubmission* | Event triggered before the submission starts, right after successful validation. The callback function receives a reference to the instance itself | An anonymous function or `null`.
251
255
  | *onSubmitEnd* | Event triggered when the submit ends, regardless of the outcome. | An anonymous function or `null`.
252
256
  | *onSuccess* | Event triggered when the request results successful. | An anonymous function or `null`.
253
257
  | *onError* | Event triggered when the response returns an error. | An anonymous function or `null`.
@@ -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: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)}};
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,h=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(h&&l.value.length>h)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",h.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,u))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:h,onStepChange:m,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeValidation:b,onBeforeSubmit:S,onBeforeSubmission:E,resetOnSuccess:y,resetLoaderOnSuccess:_,scrollOnError:L,scrollOnErrorOffset:x,preventValidation:D,preventSubmit:C,preventSubmission:q,disbleStepsTransition:w,debug:M}){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:h||null,debug:M??!1}),this.onValidationError=f??null,this.onStepChange=m??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeValidation=b??null,this.onBeforeSubmit=S??null,this.onBeforeSubmission=E??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=y??!0,this.resetLoaderOnSuccess=_??!0,this.scrollOnError=L??!0,this.scrollOnErrorOffset=x||0;const V=this.form.querySelector(".form__step.--active");if(this.currentStep=V?Number(V.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=w??!1,this.stepChanging=!1,this.preventValidation=D??!1,this.preventSubmit=C??!1,this.preventSubmission=q??!1,this.debug=M??!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(){"function"==typeof this.onBeforeValidation&&this.onBeforeValidation(this),this.onBeforeValidation||"function"!=typeof this.onBeforeSubmit||this.onBeforeSubmit(this),this.preventValidation||this.preventSubmit||this.resumeValidation()}resumeSubmit(){this.resumeValidation()}resumeValidation(){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)"function"==typeof this.onBeforeSubmission&&this.onBeforeSubmission(this),this.preventSubmission||this.resumeSubmission();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}resumeSubmission(){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()}}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(),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)}};
@@ -20,7 +20,9 @@ export default class EgoForm implements EgoFormInterface {
20
20
  onSubmitEnd: Function | null;
21
21
  onSuccess: Function | null;
22
22
  onError: Function | null;
23
+ onBeforeValidation: Function | null;
23
24
  onBeforeSubmit: Function | null;
25
+ onBeforeSubmission: Function | null;
24
26
  currentStep: number;
25
27
  currentStepOptional: boolean;
26
28
  stepChanging: boolean;
@@ -31,11 +33,15 @@ export default class EgoForm implements EgoFormInterface {
31
33
  resetLoaderOnSuccess: boolean;
32
34
  scrollOnError: boolean;
33
35
  scrollOnErrorOffset: number;
36
+ preventValidation: boolean;
34
37
  preventSubmit: boolean;
38
+ preventSubmission: boolean;
35
39
  debug: boolean;
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);
40
+ constructor({ element, classes, submitType, submitDataFormat, submitUrl, requestHeaders, fieldGroups, extraFields, serializerIgnoreList, customValidations, customValidationMessages, onStepChange, onValidationError, onSubmitStart, onSubmitEnd, onSuccess, onError, onBeforeValidation, onBeforeSubmit, onBeforeSubmission, resetOnSuccess, resetLoaderOnSuccess, scrollOnError, scrollOnErrorOffset, preventValidation, preventSubmit, preventSubmission, disbleStepsTransition, debug }: EgoFormOptions);
37
41
  submit(): void;
38
42
  resumeSubmit(): void;
43
+ resumeValidation(): void;
44
+ resumeSubmission(): void;
39
45
  submittingForm({ submitting, force }: {
40
46
  submitting: boolean;
41
47
  force?: boolean;
@@ -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: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
+ 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,h=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(h&&l.value.length>h)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",h.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,u))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:h,onStepChange:m,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeValidation:b,onBeforeSubmit:S,onBeforeSubmission:E,resetOnSuccess:y,resetLoaderOnSuccess:_,scrollOnError:L,scrollOnErrorOffset:x,preventValidation:D,preventSubmit:C,preventSubmission:q,disbleStepsTransition:w,debug:M}){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:h||null,debug:M??!1}),this.onValidationError=f??null,this.onStepChange=m??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeValidation=b??null,this.onBeforeSubmit=S??null,this.onBeforeSubmission=E??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=y??!0,this.resetLoaderOnSuccess=_??!0,this.scrollOnError=L??!0,this.scrollOnErrorOffset=x||0;const V=this.form.querySelector(".form__step.--active");if(this.currentStep=V?Number(V.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=w??!1,this.stepChanging=!1,this.preventValidation=D??!1,this.preventSubmit=C??!1,this.preventSubmission=q??!1,this.debug=M??!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(){"function"==typeof this.onBeforeValidation&&this.onBeforeValidation(this),this.onBeforeValidation||"function"!=typeof this.onBeforeSubmit||this.onBeforeSubmit(this),this.preventValidation||this.preventSubmit||this.resumeValidation()}resumeSubmit(){this.resumeValidation()}resumeValidation(){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)"function"==typeof this.onBeforeSubmission&&this.onBeforeSubmission(this),this.preventSubmission||this.resumeSubmission();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}resumeSubmission(){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()}}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(),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,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)}}}));
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"),n=e.querySelector(".form__control"),l=s?e.querySelector(".form__control:checked"):null,u=n?n.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,h=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(n||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!n?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:n,field:e,errorElement:o}),!1;if(n?.value){if(c&&n.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:n,field:e,errorElement:o}),!1;if(h&&n.value.length>h)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",h.toString())),this.displayFieldError({control:n,field:e,errorElement:o}),!1}if(s&&!l){if(!a)return this.displayFieldError({control:n,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(n&&n.value&&!this.isValidEmail({email:n.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:n,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&n?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:n,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(n&&n.value&&!this.isValidCuitCuil({num:n.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:n,field:e,errorElement:o}),!1;break;case"url":if(n&&n.value&&!this.isValidUrl({urlString:n.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:n,field:e,errorElement:o}),!1;break;case"money":if(n){const t=n.dataset.currency?n.dataset.currency:"$";if(""==n.value||n.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:n,field:e,errorElement:o}),!1}break;case"single-checkbox":if(n&&n.hasOwnProperty("checked")){if(!n.checked)return this.displayFieldError({control:n,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(n&&!i.condition(n.value,u))return o&&(o.textContent=i.message||""),this.displayFieldError({control:n,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,n=i&&i.files?i.files[0].size:0,l=i&&i.files?parseFloat((n/1048576).toFixed(1)):0;l>r||!n?(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&&(n?l<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):l>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:n,fieldGroups:l,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:h,onStepChange:m,onValidationError:f,onSubmitStart:p,onSubmitEnd:g,onSuccess:F,onError:v,onBeforeValidation:b,onBeforeSubmit:S,onBeforeSubmission:E,resetOnSuccess:y,resetLoaderOnSuccess:_,scrollOnError:L,scrollOnErrorOffset:x,preventValidation:D,preventSubmit:C,preventSubmission:q,disbleStepsTransition:w,debug:M}){this.form=e,this.submitType=s||"fetch",this.submitDataFormat=a||"formData",this.requestHeaders=n||{},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:h||null,debug:M??!1}),this.onValidationError=f??null,this.onStepChange=m??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeValidation=b??null,this.onBeforeSubmit=S??null,this.onBeforeSubmission=E??null,this.fieldGroups=l??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=y??!0,this.resetLoaderOnSuccess=_??!0,this.scrollOnError=L??!0,this.scrollOnErrorOffset=x||0;const V=this.form.querySelector(".form__step.--active");if(this.currentStep=V?Number(V.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=w??!1,this.stepChanging=!1,this.preventValidation=D??!1,this.preventSubmit=C??!1,this.preventSubmission=q??!1,this.debug=M??!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(){"function"==typeof this.onBeforeValidation&&this.onBeforeValidation(this),this.onBeforeValidation||"function"!=typeof this.onBeforeSubmit||this.onBeforeSubmit(this),this.preventValidation||this.preventSubmit||this.resumeValidation()}resumeSubmit(){this.resumeValidation()}resumeValidation(){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)"function"==typeof this.onBeforeSubmission&&this.onBeforeSubmission(this),this.preventSubmission||this.resumeSubmission();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}resumeSubmission(){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()}}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 n="";return n=s&&s>0&&r[1]&&r[1].length?o+i+r[1].slice(0,s):o,n}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(),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 n(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),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:"",n=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(n)})}))})),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)}}}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@egodesign/form",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "description": "JS/TS Form component",
6
6
  "module": "dist/js/egodesign.form.esm.min.js",