form-father 0.0.18 → 0.0.20
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/FormFather.min.js +1 -1
- package/index.d.ts +12 -6
- package/index.js +39 -12
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +12 -6
package/FormFather.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var FormFather=function(){"use strict";function t(t,e,r,n){return new(r||(r=Promise))((function(o,s){function i(t){try{a(n.next(t))}catch(t){s(t)}}function l(t){try{a(n.throw(t))}catch(t){s(t)}}function a(t){var e;t.done?o(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(i,l)}a((n=n.apply(t,e||[])).next())}))}function e(t){const e="FORM"===t.tagName?Array.from(t.elements):Array.from(t.querySelectorAll("input, select, textarea, button")),r=new FormData;return e.forEach((t=>{if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLButtonElement))return;if(!t.name||t.hasAttribute("data-no-serialize"))return;const{name:e,type:n}=t;if("file"===n)if("true"===t.getAttribute("multiple")){const n=t.files;if(n)for(let t=0;t<n.length;t++)r.append(`${e}[${t}]`,n[t])}else{const n=t.files;n&&n[0]&&r.append(e,n[0])}else{let o;if("tel"===n)o=t.value.split(/[\s()-]/).join("").replace(/^8/,"+7");else if("checkbox"===n||"radio"===n){if(!t.checked)return;o=t.value}else if("date"===n){const e=t.getAttribute("data-date-format");o=e?function(t,e){const r=new Date(t),n=t=>t.toString().padStart(2,"0"),o=n(r.getDate()),s=n(r.getMonth()+1),i=r.getFullYear().toString();return e.replace("dd",o).replace("mm",s).replace("yyyy",i)}(t.value,e):t.value}else o=t.value;r.append(e,o)}})),r}"function"==typeof SuppressedError&&SuppressedError;class r{constructor(t,e){this.$submit=null,this.waitResponse=!1,this.inputs=null,this.$licensesCheckbox=null,this.$el=t,this.options=e;this.config=Object.assign({},{onSubmit:()=>{},onResponse:()=>{},onResponseSuccess:()=>{},onResponseUnsuccess:()=>{},customTypeError:null,loaderColor:"#fff",showLoaderButton:!0,scrollToFirstErroredInput:!0,logging:!1,inputSelector:".input",inputWrapperSelector:".input-primary"},r.defaultParams,e),this.$el?(this.$submit=this.$el.querySelector('input[type="submit"], button[type="submit"]'),this.isCorrectArguments()&&this.initialization()):console.warn("Empty $el")}getOptions(){return this.options}static setDefaultParams(t){this.defaultParams=Object.assign(Object.assign({},this.defaultParams),t)}initialization(){this.inputs=this.$el.querySelectorAll(this.config.inputSelector),this.$licensesCheckbox=this.$el.querySelector('input[data-input-name="user-consent"]'),this.$licensesCheckbox&&(this.$licensesCheckbox.checked?this.enableSubmit():this.disableSubmit(),this.$licensesCheckbox.addEventListener("change",(()=>{this.$licensesCheckbox.checked?this.enableSubmit():this.disableSubmit()})));const r=()=>t(this,void 0,void 0,(function*(){var t;const r=this.$el.getAttribute("action")||"",n=(null===(t=this.$el.getAttribute("method"))||void 0===t?void 0:t.toUpperCase())||"POST",o=this.$el.getAttribute("enctype")||"application/x-www-form-urlencoded";let s=null,i={};const l=new FormData(this.$el);let a={};if(l.forEach(((t,e)=>{a[e]=t})),this.config.logging)for(const t of l.keys())console.log(l.get(t));switch("function"==typeof this.config.wrapData&&(a=this.config.wrapData(a)),o){case"application/x-www-form-urlencoded":s=new URLSearchParams(new FormData(this.$el)).toString(),i["Content-Type"]="application/x-www-form-urlencoded";break;case"multipart/form-data":s=e(this.$el);break;case"text/plain":s=Array.from(new FormData(this.$el)).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("\n"),i["Content-Type"]="text/plain";break;case"application/json":s=JSON.stringify(a),i["Content-Type"]="application/json";break;default:console.warn(`Неизвестный enctype: ${o}. Используется application/x-www-form-urlencoded.`),s=new URLSearchParams(new FormData(this.$el)).toString(),i["Content-Type"]="application/x-www-form-urlencoded"}return fetch(r,{method:n,body:s,headers:i})})),n=()=>t(this,void 0,void 0,(function*(){var t,e,n,o,s,i,l,a;if(!this.waitResponse){!0===this.config.showLoaderButton&&this.showLoader(),null===(e=(t=this.config).onSubmit)||void 0===e||e.call(t,this),this.waitResponse=!0;const c=yield r(),u=yield c.json();if(this.waitResponse=!1,!0===this.config.showLoaderButton&&this.hideLoader(),null===(o=(n=this.config).onResponse)||void 0===o||o.call(n,u,this),200===c.status)if(function(t){if(Object.prototype.hasOwnProperty.call(t,"redirect-url")&&(window.location.href=t["redirect-url"]),Object.prototype.hasOwnProperty.call(t,"reload")&&!0===t.reload&&window.location.reload(),Object.prototype.hasOwnProperty.call(t,"error-toast")){const e=document.querySelector('[data-toast-name="formErrorToast"]');if(e){const r=e.querySelector(".toast__text");r&&(r.textContent=t["error-toast"],window.Toast.showToast("formErrorToast",{removeAfterClose:!1}))}}}(u),!0===u.success)null===(i=(s=this.config).onResponseSuccess)||void 0===i||i.call(s,u,this);else if(null===(a=(l=this.config).onResponseUnsuccess)||void 0===a||a.call(l,u,this),!0===u.error&&(u["error-msg"]&&this.showErrorForm(u["error-msg"]),u.errors)){const t=[];u.errors.forEach((e=>{const r=this.$el.querySelector(`input[name="${e.name}"]`);r?(t.push(r),this.showError(r,e["error-msg"])):console.warn(`Не найдено поле с именем: ${e.name}, для вывода ошибки: ${e["error-msg"]}`)})),!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(t)}}}));this.$el.addEventListener("submit",(t=>{t.preventDefault(),this.checkInputs()&&(!this.$licensesCheckbox||this.$licensesCheckbox&&this.$licensesCheckbox.checked)&&n()}))}showError(t,e){(function(t,e){if(null==t)return null;let r=t;for(;r;){if(r.matches(e))return r;r=r.parentElement}return null})(t,this.config.inputWrapperSelector).showError(e)}showLoader(){var t;const e=`\n\t\t\t<svg height="38" viewBox="0 0 38 38" width="38" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<defs>\n\t\t\t\t<linearGradient id="a" x1="8.042%" x2="65.682%" y1="0%" y2="23.865%">\n\t\t\t\t\t<stop offset="0%" stop-color="${this.config.loaderColor}" stop-opacity="0"/>\n\t\t\t\t\t<stop offset="63.146%" stop-color="${this.config.loaderColor}" stop-opacity=".631"/>\n\t\t\t\t\t<stop offset="100%" stop-color="${this.config.loaderColor}"/>\n\t\t\t\t</linearGradient>\n\t\t\t\t</defs>\n\t\t\t\t<g fill-rule="evenodd" fill="none">\n\t\t\t\t<g transform="translate(1 1)">\n\t\t\t\t\t<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke-width="5" stroke="url(#a)"></path>\n\t\t\t\t\t<circle cx="36" cy="18" fill="${this.config.loaderColor}" r="1"></circle>\n\t\t\t\t</g>\n\t\t\t\t</g>\n\t\t\t</svg>\n\t\t`,r=document.createElement("span");r.innerHTML=e,r.className="button__loader",null===(t=this.$submit)||void 0===t||t.insertAdjacentElement("afterbegin",r),requestAnimationFrame((()=>{r.setAttribute("data-showed","")}))}hideLoader(){var t,e;null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const r=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");r&&(r.classList.remove("active"),r.removeAttribute("data-showed"),setTimeout((()=>{r.remove()}),250))}hideError(t){const e=t.parentElement;e&&e.classList.contains("input__wrapper")&&(e.getAttribute("data-type-error"),e.classList.remove("input__wrapper--error"))}scrollToFirstErroredInput(t){if(t.length>0){const e=Array.from(this.$el.querySelectorAll("input"));let r=null,n=1/0;if(t.forEach((t=>{const o=e.findIndex((e=>e===t));o<n&&(n=o,r=t)})),r){const t=r.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop,n=t.top+e-window.innerHeight/2;document.documentElement.setAttribute("data-now-scrolling",""),window.scrollTo({top:n,behavior:"smooth"}),setTimeout((()=>{document.documentElement.removeAttribute("data-now-scrolling")}),800)}}}checkInputs(){var t;let e=!0;const r={},n=[];if(null===(t=this.inputs)||void 0===t||t.forEach((t=>{var o;const s=t,i=s.getAttribute("data-check-type")||s.getAttribute("type")||"";if("SELECT"===s.tagName){const t=s.selectedOptions[0];t&&""===t.value&&s.hasAttribute("required")&&(this.showError(s,"Пустое значение"),n.push(s),e=!1)}else if((null===(o=this.config.customTypeError)||void 0===o?void 0:o.name)!==i||"TEXTAREA"===s.tagName&&!this.config.customTypeError)if(s.value.length>0){if("email"===i&&(l=s.value,/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/iu.test(l)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)),"tel"===i){const t=this.config.validatePhone||(t=>function(t){const e=[];return Array.from(t).forEach((t=>{(Number(t)||0===Number(t))&&e.push(t)})),!(e.length<11||e.length<12&&"+"===t[1])}(t.value));t(s)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)}if("url"===i&&(function(t){const e=/^https?:\/\//i.test(t)?t:`http://${t}`;try{return new URL(e),!0}catch(t){return!1}}(s.value)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)),"text"===i&&"not-numbers"===s.getAttribute("data-check-type")&&/[0-9]/.test(s.value)&&(this.showError(s,"Неверный формат"),n.push(s),e=!1),"radio"===i){const t=s.getAttribute("name")||"";r[t]||(r[t]={}),r[t][Object.keys(r[t]).length]=s}}else s.hasAttribute("required")&&(this.showError(s,"Пустое значение"),n.push(s),e=!1);var l})),Object.keys(r).length>0)for(const t in r){const e=r[t];let n=!1,o=null;for(const t in e){const r=e[t];if(r.hasAttribute("required")&&(n=!0),r.checked){if(null!==o)return!1;o=r}}if(null===o&&n)return this.showErrorForm("Необходимо указать оценку"),!1}return!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(n),e}disableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.setAttribute("disabled","")}enableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.removeAttribute("disabled")}clearInputs(){var t;null===(t=this.inputs)||void 0===t||t.forEach((t=>{var e;const r=t;"radio"===r.type?r.checked=!1:(r.value="",null===(e=r.parentElement)||void 0===e||e.classList.remove("filled"),r.dispatchEvent(new Event("input")))}))}showErrorForm(t){var e;const r=this.$el.querySelectorAll(".input__wrapper"),n=r[r.length-1];let o=this.$el.querySelector(".error-block-under-input__wrapper");o&&n.nextElementSibling===o?(o.classList.add("error-block-under-input--warning"),o.querySelector(".error-block-under-input__icon").innerHTML="\x3c!-- SVG content --\x3e",o.querySelector(".error-block-under-input__main-text").textContent=t):(o=document.createElement("div"),o.className="error-block-under-input__wrapper",o.innerHTML=`\n <div class="error-block-under-input error-block-under-input--warning">\n <div class="error-block-under-input__icon-wrapper">\n <span class="error-block-under-input__icon">\n \x3c!-- SVG content --\x3e\n </span>\n <span class="error-block-under-input__icon error-block-under-input__icon--animated" style="display:none;"></span>\n </div>\n <p class="error-block-under-input__text">\n <span class="error-block-under-input__main-text">${t}</span>\n <span class="error-block-under-input__secondary-text"></span>\n </p>\n </div>`,n.insertAdjacentElement("afterend",o)),this.$el.addEventListener("input",(()=>{this.hideErrorForm()}),{passive:!0,once:!0}),null===(e=o.querySelector(".error-block-under-input"))||void 0===e||e.classList.remove("error-block-under-input--success");const s=o.querySelector(".error-block-under-input__secondary-text");s&&(s.textContent="");const i=parseFloat(o.style.height)||0,l=parseFloat(window.getComputedStyle(o).paddingTop)||0;i!==o.querySelector(".error-block-under-input").scrollHeight+16&&(o.style.height=`${i}px`,o.style.opacity="0",o.style.paddingTop=`${l}px`)}hideErrorForm(){const t=this.$el.querySelectorAll(".input__wrapper"),e=t[t.length-1].nextElementSibling;e&&e.classList.contains("error-block-under-input__wrapper")}isCorrectArguments(){return"FORM"!==this.$el.tagName?(console.warn("$el не является тегом form"),!1):!!this.$submit||(console.warn("В форме нет кнопки с типом submit"),!1)}}return r.defaultParams={},r}();
|
|
1
|
+
var FormFather=function(){"use strict";function t(t,e,r,n){return new(r||(r=Promise))((function(o,s){function i(t){try{a(n.next(t))}catch(t){s(t)}}function l(t){try{a(n.throw(t))}catch(t){s(t)}}function a(t){var e;t.done?o(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(i,l)}a((n=n.apply(t,e||[])).next())}))}function e(t){const e="FORM"===t.tagName?Array.from(t.elements):Array.from(t.querySelectorAll("input, select, textarea, button")),r=new FormData;return e.forEach((t=>{if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLButtonElement))return;if(!t.name||t.hasAttribute("data-no-serialize"))return;const{name:e,type:n}=t;if("file"===n)if("true"===t.getAttribute("multiple")){const n=t.files;if(n)for(let t=0;t<n.length;t++)r.append(`${e}[${t}]`,n[t])}else{const n=t.files;n&&n[0]&&r.append(e,n[0])}else{let o;if("select-one"===n||"select-multiple"===n){const s=t;if("select-multiple"===n){Array.from(s.selectedOptions).map((t=>t.value)).forEach(((t,n)=>{r.append(`${e}[${n}]`,t)}))}else o=s.value,o&&r.append(e,o)}else if("tel"===n)o=t.value.split(/[\s()-]/).join("").replace(/^8/,"+7");else if("checkbox"===n||"radio"===n){if(!t.checked)return;o=t.value}else if("date"===n){const e=t.getAttribute("data-date-format");o=e?function(t,e){const r=new Date(t),n=t=>t.toString().padStart(2,"0"),o=n(r.getDate()),s=n(r.getMonth()+1),i=r.getFullYear().toString();return e.replace("dd",o).replace("mm",s).replace("yyyy",i)}(t.value,e):t.value}else o=t.value;o&&"select-one"!==n&&"select-multiple"!==n&&r.append(e,o)}})),r}"function"==typeof SuppressedError&&SuppressedError;class r{constructor(t,e){this.$submit=null,this.waitResponse=!1,this.inputs=null,this.$licensesCheckbox=null,this.$el=t,this.options=e;this.config=Object.assign({},{onSubmit:()=>{},onResponse:()=>{},onResponseSuccess:()=>{},onResponseUnsuccess:()=>{},customTypeError:null,loaderColor:"#fff",showLoaderButton:!0,scrollToFirstErroredInput:!0,logging:!1,inputSelector:".input",inputWrapperSelector:".input-primary"},r.defaultParams,e),this.$el?(this.$submit=this.$el.querySelector('input[type="submit"], button[type="submit"]'),this.isCorrectArguments()&&this.initialization()):console.warn("Empty $el")}getOptions(){return this.options}static setDefaultParams(t){this.defaultParams=Object.assign(Object.assign({},this.defaultParams),t)}initialization(){this.inputs=this.$el.querySelectorAll(this.config.inputSelector),this.$licensesCheckbox=this.$el.querySelector('input[data-input-name="user-consent"]'),this.$licensesCheckbox&&(this.$licensesCheckbox.checked?this.enableSubmit():this.disableSubmit(),this.$licensesCheckbox.addEventListener("change",(()=>{this.$licensesCheckbox.checked?this.enableSubmit():this.disableSubmit()})));const r=()=>t(this,void 0,void 0,(function*(){var t;const r=this.$el.getAttribute("action")||"",n=(null===(t=this.$el.getAttribute("method"))||void 0===t?void 0:t.toUpperCase())||"POST",o=this.$el.getAttribute("enctype")||"application/x-www-form-urlencoded";let s=null,i={};const l=e(this.$el);let a={};if(l.forEach(((t,e)=>{a[e]=t})),this.config.logging)for(const t of l.keys())console.log(l.get(t));switch("function"==typeof this.config.wrapData&&(a=this.config.wrapData(a)),o){case"application/x-www-form-urlencoded":s=new URLSearchParams(e(this.$el)).toString(),i["Content-Type"]="application/x-www-form-urlencoded";break;case"multipart/form-data":s=e(this.$el);break;case"text/plain":s=Array.from(e(this.$el)).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("\n"),i["Content-Type"]="text/plain";break;case"application/json":s=JSON.stringify(a),i["Content-Type"]="application/json";break;default:console.warn(`Неизвестный enctype: ${o}. Используется application/x-www-form-urlencoded.`),s=new URLSearchParams(e(this.$el)).toString(),i["Content-Type"]="application/x-www-form-urlencoded"}return fetch(r,{method:n,body:s,headers:i})})),n=()=>t(this,void 0,void 0,(function*(){var t,e,n,o,s,i,l,a;if(!this.waitResponse){!0===this.config.showLoaderButton&&this.showLoader(),null===(e=(t=this.config).onSubmit)||void 0===e||e.call(t,this),this.waitResponse=!0;const c=yield r(),u=yield c.json();if(this.waitResponse=!1,!0===this.config.showLoaderButton&&this.hideLoader(),null===(o=(n=this.config).onResponse)||void 0===o||o.call(n,u,this),200===c.status)if(function(t){if(Object.prototype.hasOwnProperty.call(t,"redirect-url")&&(window.location.href=t["redirect-url"]),Object.prototype.hasOwnProperty.call(t,"reload")&&!0===t.reload&&window.location.reload(),Object.prototype.hasOwnProperty.call(t,"error-toast")){const e=document.querySelector('[data-toast-name="formErrorToast"]');if(e){const r=e.querySelector(".toast__text");r&&(r.textContent=t["error-toast"],window.Toast.showToast("formErrorToast",{removeAfterClose:!1}))}}}(u),!0===u.success)null===(i=(s=this.config).onResponseSuccess)||void 0===i||i.call(s,u,this);else if(null===(a=(l=this.config).onResponseUnsuccess)||void 0===a||a.call(l,u,this),!0===u.error&&(u["error-msg"]&&this.showErrorForm(u["error-msg"]),u.errors)){const t=[];u.errors.forEach((e=>{const r=this.$el.querySelector(`input[name="${e.name}"]`);r?(t.push(r),this.showError(r,e["error-msg"])):console.warn(`Не найдено поле с именем: ${e.name}, для вывода ошибки: ${e["error-msg"]}`)})),!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(t)}}}));this.$el.addEventListener("submit",(t=>{t.preventDefault(),this.checkInputs()&&(!this.$licensesCheckbox||this.$licensesCheckbox&&this.$licensesCheckbox.checked)&&n()}))}showError(t,e){(function(t,e){if(null==t)return null;let r=t;for(;r;){if(r.matches(e))return r;r=r.parentElement}return null})(t,this.config.inputWrapperSelector).showError(e)}showLoader(){var t;const e=`\n\t\t\t<svg height="38" viewBox="0 0 38 38" width="38" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<defs>\n\t\t\t\t<linearGradient id="a" x1="8.042%" x2="65.682%" y1="0%" y2="23.865%">\n\t\t\t\t\t<stop offset="0%" stop-color="${this.config.loaderColor}" stop-opacity="0"/>\n\t\t\t\t\t<stop offset="63.146%" stop-color="${this.config.loaderColor}" stop-opacity=".631"/>\n\t\t\t\t\t<stop offset="100%" stop-color="${this.config.loaderColor}"/>\n\t\t\t\t</linearGradient>\n\t\t\t\t</defs>\n\t\t\t\t<g fill-rule="evenodd" fill="none">\n\t\t\t\t<g transform="translate(1 1)">\n\t\t\t\t\t<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke-width="5" stroke="url(#a)"></path>\n\t\t\t\t\t<circle cx="36" cy="18" fill="${this.config.loaderColor}" r="1"></circle>\n\t\t\t\t</g>\n\t\t\t\t</g>\n\t\t\t</svg>\n\t\t`,r=document.createElement("span");r.innerHTML=e,r.className="button__loader",null===(t=this.$submit)||void 0===t||t.insertAdjacentElement("afterbegin",r),requestAnimationFrame((()=>{r.setAttribute("data-showed","")}))}hideLoader(){var t,e;null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const r=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");r&&(r.classList.remove("active"),r.removeAttribute("data-showed"),setTimeout((()=>{r.remove()}),250))}hideError(t){const e=t.parentElement;e&&e.classList.contains("input__wrapper")&&(e.getAttribute("data-type-error"),e.classList.remove("input__wrapper--error"))}scrollToFirstErroredInput(t){if(t.length>0){const e=Array.from(this.$el.querySelectorAll("input"));let r=null,n=1/0;if(t.forEach((t=>{const o=e.findIndex((e=>e===t));o<n&&(n=o,r=t)})),r){const t=r.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop,n=t.top+e-window.innerHeight/2;document.documentElement.setAttribute("data-now-scrolling",""),window.scrollTo({top:n,behavior:"smooth"}),setTimeout((()=>{document.documentElement.removeAttribute("data-now-scrolling")}),800)}}}checkInputs(){var t;let e=!0;const r={},n=[];if(null===(t=this.inputs)||void 0===t||t.forEach((t=>{var o;const s=t,i=s.getAttribute("data-check-type")||s.getAttribute("type")||"";if("SELECT"===s.tagName){const t=s.selectedOptions[0];t&&""===t.value&&s.hasAttribute("required")&&(this.showError(s,"Пустое значение"),n.push(s),e=!1)}else if("checkbox"===i)s.hasAttribute("required")&&!s.checked&&(this.showError(s,"Необходимо согласие"),n.push(s),e=!1);else if((null===(o=this.config.customTypeError)||void 0===o?void 0:o.name)!==i||"TEXTAREA"===s.tagName&&!this.config.customTypeError)if(s.value.length>0){if("email"===i&&(l=s.value,/^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/iu.test(l)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)),"tel"===i){const t=this.config.validatePhone||(t=>function(t){const e=[];return Array.from(t).forEach((t=>{(Number(t)||0===Number(t))&&e.push(t)})),!(e.length<11||e.length<12&&"+"===t[1])}(t.value));t(s)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)}if("url"===i&&(function(t){const e=/^https?:\/\//i.test(t)?t:`http://${t}`;try{return new URL(e),!0}catch(t){return!1}}(s.value)||(this.showError(s,"Неверный формат"),n.push(s),e=!1)),"text"===i&&"not-numbers"===s.getAttribute("data-check-type")&&/[0-9]/.test(s.value)&&(this.showError(s,"Неверный формат"),n.push(s),e=!1),"radio"===i){const t=s.getAttribute("name")||"";r[t]||(r[t]={}),r[t][Object.keys(r[t]).length]=s}}else s.hasAttribute("required")&&(this.showError(s,"Пустое значение"),n.push(s),e=!1);var l})),Object.keys(r).length>0)for(const t in r){const e=r[t];let n=!1,o=null;for(const t in e){const r=e[t];if(r.hasAttribute("required")&&(n=!0),r.checked){if(null!==o)return!1;o=r}}if(null===o&&n)return this.showErrorForm("Необходимо указать оценку"),!1}return!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(n),e}disableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.setAttribute("disabled","")}enableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.removeAttribute("disabled")}clearInputs(){var t;null===(t=this.inputs)||void 0===t||t.forEach((t=>{var e;const r=t;"radio"===r.type?r.checked=!1:(r.value="",null===(e=r.parentElement)||void 0===e||e.classList.remove("filled"),r.dispatchEvent(new Event("input")))}))}showErrorForm(t){var e;const r=this.$el.querySelectorAll(".input__wrapper"),n=r[r.length-1];let o=this.$el.querySelector(".error-block-under-input__wrapper");o&&n.nextElementSibling===o?(o.classList.add("error-block-under-input--warning"),o.querySelector(".error-block-under-input__icon").innerHTML="\x3c!-- SVG content --\x3e",o.querySelector(".error-block-under-input__main-text").textContent=t):(o=document.createElement("div"),o.className="error-block-under-input__wrapper",o.innerHTML=`\n <div class="error-block-under-input error-block-under-input--warning">\n <div class="error-block-under-input__icon-wrapper">\n <span class="error-block-under-input__icon">\n \x3c!-- SVG content --\x3e\n </span>\n <span class="error-block-under-input__icon error-block-under-input__icon--animated" style="display:none;"></span>\n </div>\n <p class="error-block-under-input__text">\n <span class="error-block-under-input__main-text">${t}</span>\n <span class="error-block-under-input__secondary-text"></span>\n </p>\n </div>`,n.insertAdjacentElement("afterend",o)),this.$el.addEventListener("input",(()=>{this.hideErrorForm()}),{passive:!0,once:!0}),null===(e=o.querySelector(".error-block-under-input"))||void 0===e||e.classList.remove("error-block-under-input--success");const s=o.querySelector(".error-block-under-input__secondary-text");s&&(s.textContent="");const i=parseFloat(o.style.height)||0,l=parseFloat(window.getComputedStyle(o).paddingTop)||0;i!==o.querySelector(".error-block-under-input").scrollHeight+16&&(o.style.height=`${i}px`,o.style.opacity="0",o.style.paddingTop=`${l}px`)}hideErrorForm(){const t=this.$el.querySelectorAll(".input__wrapper"),e=t[t.length-1].nextElementSibling;e&&e.classList.contains("error-block-under-input__wrapper")}isCorrectArguments(){return"FORM"!==this.$el.tagName?(console.warn("$el не является тегом form"),!1):!!this.$submit||(console.warn("В форме нет кнопки с типом submit"),!1)}}return r.defaultParams={},r}();
|
|
2
2
|
//# sourceMappingURL=FormFather.min.js.map
|
package/index.d.ts
CHANGED
|
@@ -39,9 +39,15 @@ interface FormOptions {
|
|
|
39
39
|
logging?: boolean;
|
|
40
40
|
/** Селектор поля ввода данных. Таких как textarea, input, select, ... . По умолчанию `.input`. */
|
|
41
41
|
inputSelector?: string;
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Селектор поля обёртки над полем ввода, у которого реализован публичный метод `showError`. По умолчанию
|
|
44
|
+
* `.input-primary`.
|
|
45
|
+
*/
|
|
43
46
|
inputWrapperSelector?: string;
|
|
44
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Пользовательская функция для проверки телефона. По умолчанию стандартный `isPhoneValid` для русских номеров
|
|
49
|
+
* телефонов.
|
|
50
|
+
*/
|
|
45
51
|
validatePhone?: (input: HTMLInputElement) => boolean;
|
|
46
52
|
/** Функция для обёртки отправляемых данных. */
|
|
47
53
|
wrapData?: (data: Record<string, any>) => Record<string, any>;
|
|
@@ -69,11 +75,11 @@ declare class Form {
|
|
|
69
75
|
constructor($el: HTMLElement, options: FormOptions);
|
|
70
76
|
getOptions(): FormOptions;
|
|
71
77
|
/**
|
|
72
|
-
* Обновляет параметры по умолчанию для настроек формы.
|
|
73
|
-
*
|
|
78
|
+
* Обновляет параметры по умолчанию для настроек формы. Метод объединяет переданные параметры с уже существующими
|
|
79
|
+
* параметрами по умолчанию.
|
|
74
80
|
*
|
|
75
|
-
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров.
|
|
76
|
-
*
|
|
81
|
+
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров. Можно передать только те
|
|
82
|
+
* свойства, которые необходимо обновить; остальные сохранятся без изменений.
|
|
77
83
|
*/
|
|
78
84
|
static setDefaultParams(params: Partial<FormOptions>): void;
|
|
79
85
|
private initialization;
|
package/index.js
CHANGED
|
@@ -158,7 +158,22 @@ function serializeToFormData($element) {
|
|
|
158
158
|
}
|
|
159
159
|
else {
|
|
160
160
|
let value;
|
|
161
|
-
if (type === '
|
|
161
|
+
if (type === 'select-one' || type === 'select-multiple') {
|
|
162
|
+
// Обработка select элементов
|
|
163
|
+
const select = element;
|
|
164
|
+
if (type === 'select-multiple') {
|
|
165
|
+
const selectedOptions = Array.from(select.selectedOptions).map(option => option.value);
|
|
166
|
+
selectedOptions.forEach((val, index) => {
|
|
167
|
+
data.append(`${name}[${index}]`, val);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
value = select.value;
|
|
172
|
+
if (value)
|
|
173
|
+
data.append(name, value);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (type === 'tel') {
|
|
162
177
|
value = element.value
|
|
163
178
|
.split(/[\s()-]/)
|
|
164
179
|
.join('')
|
|
@@ -176,7 +191,9 @@ function serializeToFormData($element) {
|
|
|
176
191
|
else {
|
|
177
192
|
value = element.value;
|
|
178
193
|
}
|
|
179
|
-
|
|
194
|
+
if (value && type !== 'select-one' && type !== 'select-multiple') {
|
|
195
|
+
data.append(name, value);
|
|
196
|
+
}
|
|
180
197
|
}
|
|
181
198
|
});
|
|
182
199
|
return data;
|
|
@@ -255,11 +272,11 @@ class Form {
|
|
|
255
272
|
return this.options;
|
|
256
273
|
}
|
|
257
274
|
/**
|
|
258
|
-
* Обновляет параметры по умолчанию для настроек формы.
|
|
259
|
-
*
|
|
275
|
+
* Обновляет параметры по умолчанию для настроек формы. Метод объединяет переданные параметры с уже существующими
|
|
276
|
+
* параметрами по умолчанию.
|
|
260
277
|
*
|
|
261
|
-
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров.
|
|
262
|
-
*
|
|
278
|
+
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров. Можно передать только те
|
|
279
|
+
* свойства, которые необходимо обновить; остальные сохранятся без изменений.
|
|
263
280
|
*/
|
|
264
281
|
static setDefaultParams(params) {
|
|
265
282
|
this.defaultParams = Object.assign(Object.assign({}, this.defaultParams), params);
|
|
@@ -287,7 +304,7 @@ class Form {
|
|
|
287
304
|
let body = null;
|
|
288
305
|
let headers = {};
|
|
289
306
|
// Сбор данных из формы
|
|
290
|
-
const formData =
|
|
307
|
+
const formData = serializeToFormData(this.$el);
|
|
291
308
|
let data = {};
|
|
292
309
|
formData.forEach((value, key) => {
|
|
293
310
|
data[key] = value;
|
|
@@ -302,7 +319,7 @@ class Form {
|
|
|
302
319
|
}
|
|
303
320
|
switch (enctype) {
|
|
304
321
|
case 'application/x-www-form-urlencoded':
|
|
305
|
-
body = new URLSearchParams(
|
|
322
|
+
body = new URLSearchParams(serializeToFormData(this.$el)).toString();
|
|
306
323
|
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
307
324
|
break;
|
|
308
325
|
case 'multipart/form-data':
|
|
@@ -310,7 +327,7 @@ class Form {
|
|
|
310
327
|
// ВАЖНО: Не указываем Content-Type, т.к. браузер сам добавит с корректной границей!
|
|
311
328
|
break;
|
|
312
329
|
case 'text/plain':
|
|
313
|
-
body = Array.from(
|
|
330
|
+
body = Array.from(serializeToFormData(this.$el))
|
|
314
331
|
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
315
332
|
.join('\n');
|
|
316
333
|
headers['Content-Type'] = 'text/plain';
|
|
@@ -321,7 +338,7 @@ class Form {
|
|
|
321
338
|
break;
|
|
322
339
|
default:
|
|
323
340
|
console.warn(`Неизвестный enctype: ${enctype}. Используется application/x-www-form-urlencoded.`);
|
|
324
|
-
body = new URLSearchParams(
|
|
341
|
+
body = new URLSearchParams(serializeToFormData(this.$el)).toString();
|
|
325
342
|
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
326
343
|
}
|
|
327
344
|
return fetch(action, {
|
|
@@ -464,7 +481,7 @@ class Form {
|
|
|
464
481
|
if ($firstInputOnForm) {
|
|
465
482
|
const rect = $firstInputOnForm.getBoundingClientRect();
|
|
466
483
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
467
|
-
const scrollTargetY = rect.top + scrollTop -
|
|
484
|
+
const scrollTargetY = rect.top + scrollTop - window.innerHeight / 2;
|
|
468
485
|
document.documentElement.setAttribute('data-now-scrolling', '');
|
|
469
486
|
window.scrollTo({
|
|
470
487
|
top: scrollTargetY,
|
|
@@ -500,6 +517,13 @@ class Form {
|
|
|
500
517
|
isCorrect = false;
|
|
501
518
|
}
|
|
502
519
|
}
|
|
520
|
+
else if (inputType === 'checkbox') {
|
|
521
|
+
if ($input.hasAttribute('required') && !$input.checked) {
|
|
522
|
+
this.showError($input, 'Необходимо согласие');
|
|
523
|
+
inputsList.push($input);
|
|
524
|
+
isCorrect = false;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
503
527
|
else if (((_a = this.config.customTypeError) === null || _a === void 0 ? void 0 : _a.name) !== inputType ||
|
|
504
528
|
($input.tagName === 'TEXTAREA' && !this.config.customTypeError)) {
|
|
505
529
|
if ($input.value.length > 0) {
|
|
@@ -511,7 +535,10 @@ class Form {
|
|
|
511
535
|
}
|
|
512
536
|
}
|
|
513
537
|
if (inputType === 'tel') {
|
|
514
|
-
const isPhoneValidChecker = this.config.validatePhone ||
|
|
538
|
+
const isPhoneValidChecker = this.config.validatePhone ||
|
|
539
|
+
(($input) => {
|
|
540
|
+
return isPhoneValid($input.value);
|
|
541
|
+
});
|
|
515
542
|
if (!isPhoneValidChecker($input)) {
|
|
516
543
|
this.showError($input, 'Неверный формат');
|
|
517
544
|
inputsList.push($input);
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -39,9 +39,15 @@ interface FormOptions {
|
|
|
39
39
|
logging?: boolean;
|
|
40
40
|
/** Селектор поля ввода данных. Таких как textarea, input, select, ... . По умолчанию `.input`. */
|
|
41
41
|
inputSelector?: string;
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Селектор поля обёртки над полем ввода, у которого реализован публичный метод `showError`. По умолчанию
|
|
44
|
+
* `.input-primary`.
|
|
45
|
+
*/
|
|
43
46
|
inputWrapperSelector?: string;
|
|
44
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Пользовательская функция для проверки телефона. По умолчанию стандартный `isPhoneValid` для русских номеров
|
|
49
|
+
* телефонов.
|
|
50
|
+
*/
|
|
45
51
|
validatePhone?: (input: HTMLInputElement) => boolean;
|
|
46
52
|
/** Функция для обёртки отправляемых данных. */
|
|
47
53
|
wrapData?: (data: Record<string, any>) => Record<string, any>;
|
|
@@ -69,11 +75,11 @@ export default class Form {
|
|
|
69
75
|
constructor($el: HTMLElement, options: FormOptions);
|
|
70
76
|
getOptions(): FormOptions;
|
|
71
77
|
/**
|
|
72
|
-
* Обновляет параметры по умолчанию для настроек формы.
|
|
73
|
-
*
|
|
78
|
+
* Обновляет параметры по умолчанию для настроек формы. Метод объединяет переданные параметры с уже существующими
|
|
79
|
+
* параметрами по умолчанию.
|
|
74
80
|
*
|
|
75
|
-
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров.
|
|
76
|
-
*
|
|
81
|
+
* @param {Partial<FormOptions>} params - Объект, содержащий новые значения параметров. Можно передать только те
|
|
82
|
+
* свойства, которые необходимо обновить; остальные сохранятся без изменений.
|
|
77
83
|
*/
|
|
78
84
|
static setDefaultParams(params: Partial<FormOptions>): void;
|
|
79
85
|
private initialization;
|