@egodesign/form 1.7.1 → 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
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
| *
|
|
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:F,onSuccess:g,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,preventSubmit:_,disbleStepsTransition:L,debug:x}){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:x??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=F??null,this.onSuccess=g??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const D=this.form.querySelector(".form__step.--active");if(this.currentStep=D?Number(D.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=L??!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=x??!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})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');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(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}};
|
|
1
|
+
"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,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;
|
|
@@ -30,11 +32,16 @@ export default class EgoForm implements EgoFormInterface {
|
|
|
30
32
|
resetOnSuccess: boolean;
|
|
31
33
|
resetLoaderOnSuccess: boolean;
|
|
32
34
|
scrollOnError: boolean;
|
|
35
|
+
scrollOnErrorOffset: number;
|
|
36
|
+
preventValidation: boolean;
|
|
33
37
|
preventSubmit: boolean;
|
|
38
|
+
preventSubmission: boolean;
|
|
34
39
|
debug: boolean;
|
|
35
|
-
constructor({ element, classes, submitType, submitDataFormat, submitUrl, requestHeaders, fieldGroups, extraFields, serializerIgnoreList, customValidations, customValidationMessages, onStepChange, onValidationError, onSubmitStart, onSubmitEnd, onSuccess, onError, onBeforeSubmit, resetOnSuccess, resetLoaderOnSuccess, scrollOnError, 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);
|
|
36
41
|
submit(): void;
|
|
37
42
|
resumeSubmit(): void;
|
|
43
|
+
resumeValidation(): void;
|
|
44
|
+
resumeSubmission(): void;
|
|
38
45
|
submittingForm({ submitting, force }: {
|
|
39
46
|
submitting: boolean;
|
|
40
47
|
force?: boolean;
|
|
@@ -75,5 +82,6 @@ export default class EgoForm implements EgoFormInterface {
|
|
|
75
82
|
togglePasswordVisibility({ btn }: {
|
|
76
83
|
btn: HTMLElement;
|
|
77
84
|
}): void;
|
|
78
|
-
declareHandlers(): void;
|
|
85
|
+
declareHandlers(isRefresh?: boolean): void;
|
|
86
|
+
refresh(): void;
|
|
79
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,m=e.dataset.maxLength?Number(e.dataset.maxLength):null;if(l||this.throwError("control not found."),u||this.throwError("control name not found."),this.debug&&i(`validating field "${u}"`),r&&!l?.value)return o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(l?.value){if(c&&l.value.length<c)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.minLength.replace("[[var]]",c.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1;if(m&&l.value.length>m)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.maxLength.replace("[[var]]",m.toString())),this.displayFieldError({control:l,field:e,errorElement:o}),!1}if(s&&!n){if(!a)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}else{switch(t){case"email":if(l&&l.value&&!this.isValidEmail({email:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.email.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"password_repeat":{const t=document.getElementById("password");if(t&&l?.value!=t?.value)return o&&this.validationMessages&&(o.textContent=this.validationMessages.password_repeat.unequal),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break}case"cuil":case"cuit":if(l&&l.value&&!this.isValidCuitCuil({num:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.cuil.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"url":if(l&&l.value&&!this.isValidUrl({urlString:l.value}))return o&&this.validationMessages&&(o.textContent=this.validationMessages.url.invalid),this.displayFieldError({control:l,field:e,errorElement:o}),!1;break;case"money":if(l){const t=l.dataset.currency?l.dataset.currency:"$";if(""==l.value||l.value==t)return o&&this.validationMessages&&(o.textContent=this.validationMessages.default.empty),this.displayFieldError({control:l,field:e,errorElement:o}),!1}break;case"single-checkbox":if(l&&l.hasOwnProperty("checked")){if(!l.checked)return this.displayFieldError({control:l,field:e,errorElement:o}),o&&this.validationMessages&&u&&(o.textContent=this.validationMessages[u]?this.validationMessages[u].empty:this.validationMessages.default.empty),!1}}for(const i of d)if(t===i)for(const i of this.customValidations[t])if(l&&!i.condition(l.value))return o&&(o.textContent=i.message||""),this.displayFieldError({control:l,field:e,errorElement:o}),!1}return!0}isValidEmail({email:e}){return/(?!.*\.{2})^([a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i.test(e.toLowerCase())}isValidCuitCuil({num:e}){const t=[5,4,3,2,7,6,5,4,3,2];let i=e.toString().replace(/[^0-9]/g,"").split("");if(11!=i.length)return!1;i=i.map((e=>Number(e)));const s=Number(i.pop());let r=11-i.reduce(((e,i,s)=>e+Number(i)*t[s]),0)%11;return 10==r&&(r=9),11==r&&(r=0),r==s}isValidUrl({urlString:e}){return!!new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$","i").test(e)}isValidFileSize({field:e}){let t=null;const i=e.querySelector(".form__control"),s=Number(e.dataset.minSize),r=Number(e.dataset.maxSize),a=e.querySelector(".form__error"),o=i&&i.files?i.files[0].name:null,l=i&&i.files?i.files[0].size:0,n=i&&i.files?parseFloat((l/1048576).toFixed(1)):0;n>r||!l?(i&&(i.value="",i.setAttribute("aria-invalid","true")),e.classList.remove("--has-file"),e.classList.add(this.classes.fieldHasError)):o?e.classList.add("--has-file"):e.classList.remove("--has-file"),this.validationMessages&&(l?n<s?t=this.validationMessages.file.min_size.replace("[[var]]",s+" MB"):n>r&&(t=this.validationMessages.file.max_size.replace("[[var]]",r+" MB")):t=this.validationMessages.file.empty),t&&a&&(a.textContent=t,this.displayFieldError({control:i,field:e,errorElement:a}))}displayFieldError({control:e,field:t,errorElement:i}){e&&(e.setAttribute("aria-invalid","true"),t.classList.add(this.classes.fieldHasError),this.classes.controlHasError&&e.classList.add(this.classes.controlHasError),i&&i.classList.remove(this.classes.hiddenErrorMessage))}clearControlError({control:e}){if(!e)return;e.setAttribute("aria-invalid","false"),this.classes.controlHasError&&e.classList.remove(this.classes.controlHasError);const i=t({element:e,className:"form__field"}),s=i?.querySelector(".form__error");i?.classList.remove(this.classes.fieldHasError),s&&(s.textContent="",s.classList.add(this.classes.hiddenErrorMessage))}realTimeValidations({form:e}){e.querySelectorAll('.form__field[data-type="file"]').forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("change",(t=>{t.stopPropagation(),this.isValidFileSize({field:e})}))}))}throwError(e){throw new Error(`EgoForm Error: ${e}`)}}class a{constructor({element:e,classes:t,submitType:s,submitDataFormat:a,submitUrl:o,requestHeaders:l,fieldGroups:n,extraFields:u,serializerIgnoreList:d,customValidations:c,customValidationMessages:m,onStepChange:h,onValidationError:f,onSubmitStart:p,onSubmitEnd:F,onSuccess:g,onError:v,onBeforeSubmit:b,resetOnSuccess:E,resetLoaderOnSuccess:S,scrollOnError:y,preventSubmit:_,disbleStepsTransition:L,debug:x}){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:x??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=F??null,this.onSuccess=g??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const D=this.form.querySelector(".form__step.--active");if(this.currentStep=D?Number(D.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=L??!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=x??!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})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');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(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}}export{a as default};
|
|
1
|
+
const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),l=e.querySelector(".form__control"),n=s?e.querySelector(".form__control:checked"):null,u=l?l.getAttribute("name"):null,d=Object.keys(this.customValidations),c=e.dataset.minLength?Number(e.dataset.minLength):null,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,preventSubmit:_,disbleStepsTransition:L,debug:x}){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:x??!1}),this.onValidationError=f??null,this.onStepChange=h??null,this.onSubmitStart=p??null,this.onSubmitEnd=g??null,this.onSuccess=F??null,this.onError=v??null,this.onBeforeSubmit=b??null,this.fieldGroups=n??null,this.extraFields=u??[],this.hasFile=!1,this.serializerIgnoreList=d||[],this.resetOnSuccess=E??!0,this.resetLoaderOnSuccess=S??!0,this.scrollOnError=y??!0;const D=this.form.querySelector(".form__step.--active");if(this.currentStep=D?Number(D.dataset.step):0,this.currentStepOptional=!1,this.disbleStepsTransition=L??!1,this.stepChanging=!1,this.preventSubmit=_??!1,this.debug=x??!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})&&e.scrollIntoView({behavior:"smooth"})}}submittingForm({submitting:e,force:t=!1}){let i=document.getElementsByTagName("body").item(0);e?(this.form.classList.add(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.add(this.classes.buttonSubmittingState),i&&i.classList.add("--block"),"function"==typeof this.onSubmitStart&&this.onSubmitStart()):((this.resetLoaderOnSuccess||t)&&(this.form.classList.remove(this.classes.formSubmittingState),this.submitBtn&&this.submitBtn.classList.remove(this.classes.buttonSubmittingState),i&&i.classList.remove("--block")),"function"==typeof this.onSubmitEnd&&this.onSubmitEnd())}serializeData({returnFormData:e=!1}){const t=new FormData(this.form),i={};for(const e of t){const[t,s]=e;if(!this.serializerIgnoreList.includes(t)){if(s instanceof File&&!s.size&&!s.name)continue;i.hasOwnProperty(t)?i[t]=[...i[t],s]:i[t]=s}}if(this.fieldGroups)for(const e in this.fieldGroups)if(Object.hasOwnProperty.call(this.fieldGroups,e)){let s=[{}];for(const r of this.fieldGroups[e])s[0][r]=t.get(r),delete i[r];i[e]=s}if(this.extraFields.length)for(const e of this.extraFields)e.hasOwnProperty("name")&&e.hasOwnProperty("value")&&(t.append(e.name,e.value),i[e.name]=e.value);return e?t:JSON.stringify(i)}reset(){this.form.reset(),this.form.querySelectorAll(".form__field").forEach((e=>e.classList.remove("--filled",`${this.classes.fieldHasError}`))),this.form.querySelectorAll(".form__control").forEach((e=>e.setAttribute("aria-invalid","false"))),this.currentStep&&this.changeStep({step:1})}changeStep({step:t}){if(!this.stepChanging){const i=this.currentStepOptional?this.currentStep.toString()+"b":this.currentStep.toString(),s=this.form.querySelector('[data-step="'+i+'"]'),r=s?.querySelectorAll(`.${this.classes.requiredField}`),a="next"===t?this.currentStep+1:"prev"!==t||this.currentStepOptional?"optional"===t?this.currentStep+"b":this.currentStep:this.currentStep-1,o=this.form.querySelector('[data-step="'+a+'"]');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(){const e=this;if(!this.submitBtn)throw new Error(`There's no submit button in this form "${this.form.id}".`);this.submitBtn.addEventListener("click",(function(t){t.preventDefault(),"function"==typeof e.onBeforeSubmit&&e.onBeforeSubmit(e),e.submit()})),this.validator.realTimeValidations({form:this.form}),this.form.querySelectorAll(`.form__field.${this.classes.validateOnBlur}`).forEach((e=>{e.querySelector(".form__control")?.addEventListener("blur",(()=>{this.validator.validateField({field:e})||(this.isValid=!1)}))})),this.form.querySelectorAll(`.form__field.${this.classes.validateOnInput}`).forEach((e=>{const t=e.querySelector(".form__control");t?.addEventListener("input",(()=>{this.validator.validateField({field:e})&&this.validator.clearControlError({control:t})}))})),this.form.querySelectorAll(".form__next-step").forEach((t=>{t.addEventListener("click",e.nextStep.bind(e))})),this.form.querySelectorAll(".form__optional-step").forEach((t=>{t.addEventListener("click",e.optionalStep.bind(e))})),this.form.querySelectorAll(".form__prev-step").forEach((t=>{t.addEventListener("click",e.prevStep.bind(e))})),this.form.querySelectorAll(".form__control").forEach((e=>{this.isControlFilled({control:e}),e.addEventListener("keyup",(()=>{this.isControlFilled({control:e})})),e.addEventListener("change",(()=>{this.isControlFilled({control:e})}))})),this.form.querySelectorAll(".form__control").forEach((e=>{e.addEventListener("focus",(()=>{this.validator.clearControlError({control:e})}))})),this.form.querySelectorAll("."+this.classes.clearFieldError).forEach((i=>{i.addEventListener("click",(()=>{const s=t({element:i,className:"form__field"});s&&e.validator.clearControlError({control:s.querySelector(".form__control")})}))})),this.form.querySelectorAll(".form__field.--number input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:"",a=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",o=s&&s.dataset.decimals?s.dataset.decimals:"";function l(){e.value=i.filterNumber({value:e.value,ignoreList:[a]})}e.addEventListener("focus",l),e.addEventListener("input",l),e.addEventListener("paste",l),e.addEventListener("blur",(()=>{e.value=r?i.filterFormattedQuantity({num:e.value,thousands:r,decimals:a,decimalSteps:parseInt(o)}):i.filterNumber({value:e.value})}))})),this.form.querySelectorAll(".form__field.--money-amount input").forEach((e=>{const i=this,s=t({element:e,className:"form__field"}),r=s&&s.dataset.currency?s.dataset.currency:"$",a=s&&s.dataset.thousandsSeparator?s.dataset.thousandsSeparator:".",o=s&&s.dataset.decimalSeparator?s.dataset.decimalSeparator:"",l=s&&s.dataset.decimals?s.dataset.decimals:"";function n(){e.value=i.filterNumber({value:e.value,ignoreList:[o]})}e.addEventListener("focus",n),e.addEventListener("input",n),e.addEventListener("paste",n),e.addEventListener("blur",(()=>{e.value=this.filterMoneyAmount({num:e.value,currency:r,thousands:a,decimals:o,decimalSteps:parseInt(l)})}))})),this.form.querySelectorAll(".form__field.--phone input").forEach((e=>{e.addEventListener("input",(()=>{e.value=this.filterPhoneNumber({number:e.value})})),e.addEventListener("paste",(()=>{e.value=this.filterPhoneNumber({number:e.value})}))})),this.form.querySelectorAll(".form__toggle-password-visibility").forEach((e=>{e.addEventListener("click",(()=>this.togglePasswordVisibility({btn:e})))}))}}}));
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).egodesign=e.egodesign||{},e.egodesign.form=t())}(this,(function(){"use strict";const e=({element:e,enter:t,time:i,displayType:s,callback:r})=>{e.style.opacity=t?"0":"1",t&&(e.style.display=s);let a=(new Date).getTime();!function s(){e.style.opacity=t?(+e.style.opacity+((new Date).getTime()-a)/i).toString():(+e.style.opacity-((new Date).getTime()-a)/i).toString(),a=(new Date).getTime(),t&&Number(e.style.opacity)<1||!t&&Number(e.style.opacity)>0?requestAnimationFrame(s)||setTimeout(s,16):(t||(e.style.display="none"),r&&"function"==typeof r&&r())}()},t=({element:e,className:t})=>{if(!e)return null;for(;e&&!e.classList.contains(t);)e=e.parentElement?e.parentElement:null;return e};function i(e,t="log"){"log"==t?console.log("::EgoForm:: "+e):"data"==t&&(console.log("::EgoForm:: DATA"),console.table(e))}const s={default:{empty:"Campo requerido.",invalid:"Campo nó válido.",minLength:"Debe tener al menos [[var]] caracteres.",maxLength:"Debe tener como máximo [[var]] caracteres."},email:{empty:"El email es requerido.",invalid:"El email no es válido."},message:{empty:"El mensaje es requerido."},password:{empty:"Ingrese una contraseña."},password_repeat:{empty:"Debe repetir la contraseña.",unequal:"Las contraseñas no coindicen."},cuil:{empty:"Campo requerido.",min:"El número debe tener exactamente 11 dígitos.",invalid:"El número ingresado no es válido."},url:{empty:"Campo requerido.",invalid:"URL no válida."},file:{empty:"Campo requerido",min_size:"El tamaño mínimo es [[var]]",max_size:"El tamaño máximo es [[var]]"}};class r{constructor({customValidations:e,classes:t,customValidationMessages:i,debug:r}){this.customValidations=e,this.validationMessages={...s,...i},this.classes=t,this.debug=r}validateField({field:e}){const t=e.dataset.type||"",s=["radio","checkbox"].includes(t),r=e.classList.contains(this.classes.requiredField),a=e.classList.contains(this.classes.requiredIfFilledField),o=e.querySelector(".form__error"),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)}}}));
|
|
@@ -13,3 +13,4 @@ export declare const isInViewport: ({ element }: {
|
|
|
13
13
|
element: HTMLElement;
|
|
14
14
|
}) => boolean;
|
|
15
15
|
export declare function showLog(msg: string, type?: 'log' | 'data'): void;
|
|
16
|
+
export declare function scrollIntoViewWithOffset(element: HTMLElement | null, offset: number): void;
|