form-father 0.0.9 → 0.0.11
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.js +90 -15
- package/index.js.map +1 -1
- package/package.json +37 -8
package/FormFather.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var FormFather=function(){"use strict";function t(t,e,r,o){return new(r||(r=Promise))((function(n,s){function i(t){try{c(o.next(t))}catch(t){s(t)}}function l(t){try{c(o.throw(t))}catch(t){s(t)}}function c(t){var e;t.done?n(t.value):(e=t.value,e instanceof r?e:new r((function(t){t(e)}))).then(i,l)}c((o=o.apply(t,e||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class e{constructor(t,r){this.$submit=null,this.waitResponse=!1,this.inputs=null,this.$licensesCheckbox=null,this.$el=t,this.options=r;this.config=Object.assign({},{onSubmit:()=>{},onResponse:()=>{},onResponseSuccess:()=>{},onResponseUnsuccess:()=>{},customTypeError:null,loaderColor:"#fff",showLoaderButton:!0,scrollToFirstErroredInput:!0,logging:!1},e.defaultParams,r),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(".input"),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 e=()=>t(this,void 0,void 0,(function*(){var t;const e=this.$el.getAttribute("action")||"",r=(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 n=null,s={};const i=new FormData(this.$el);let l={};switch(i.forEach(((t,e)=>{l[e]=t})),"function"==typeof this.config.wrapData&&(l=this.config.wrapData(l)),o){case"application/x-www-form-urlencoded":n=new URLSearchParams(l).toString(),s["Content-Type"]="application/x-www-form-urlencoded";break;case"multipart/form-data":n=new FormData(this.$el);break;case"text/plain":n=Object.entries(l).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("\n"),s["Content-Type"]="text/plain";break;default:n=JSON.stringify(l),s["Content-Type"]="application/json"}return fetch(e,{method:r,body:n,headers:s})})),r=()=>t(this,void 0,void 0,(function*(){var t,r,o,n,s,i,l,c;if(!this.waitResponse){!0===this.config.showLoaderButton&&this.showLoader(),null===(r=(t=this.config).onSubmit)||void 0===r||r.call(t,this),this.waitResponse=!0;const a=yield e(),u=yield a.json();if(this.waitResponse=!1,!0===this.config.showLoaderButton&&this.hideLoader(),null===(n=(o=this.config).onResponse)||void 0===n||n.call(o,u,this),200===a.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===(c=(l=this.config).onResponseUnsuccess)||void 0===c||c.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)&&r()}))}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,"input-primary").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,o=1/0;if(t.forEach((t=>{const n=e.findIndex((e=>e===t));n<o&&(o=n,r=t)})),r){const t=r.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop,o=t.top+e-window.innerHeight/2;document.documentElement.setAttribute("data-now-scrolling",""),window.scrollTo({top:o,behavior:"smooth"}),setTimeout((()=>{document.documentElement.removeAttribute("data-now-scrolling")}),800)}}}checkInputs(){var t;let e=!0;const r={},o=[];if(null===(t=this.inputs)||void 0===t||t.forEach((t=>{var n;const s=t,i=s.getAttribute("data-check-type")||s.getAttribute("type")||"";if((null===(n=this.config.customTypeError)||void 0===n?void 0:n.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,"Неверный формат"),o.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,"Неверный формат"),o.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,"Неверный формат"),o.push(s),e=!1)),"text"===i&&"not-numbers"===s.getAttribute("data-check-type")&&/[0-9]/.test(s.value)&&(this.showError(s,"Неверный формат"),o.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,"Пустое значение"),o.push(s),e=!1);var l})),Object.keys(r).length>0)for(const t in r){const e=r[t];let o=!1,n=null;for(const t in e){const r=e[t];if(r.hasAttribute("required")&&(o=!0),r.checked){if(null!==n)return!1;n=r}}if(null===n&&o)return this.showErrorForm("Необходимо указать оценку"),!1}return!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(o),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"),o=r[r.length-1];let n=this.$el.querySelector(".error-block-under-input__wrapper");n&&o.nextElementSibling===n?(n.classList.add("error-block-under-input--warning"),n.querySelector(".error-block-under-input__icon").innerHTML="\x3c!-- SVG content --\x3e",n.querySelector(".error-block-under-input__main-text").textContent=t):(n=document.createElement("div"),n.className="error-block-under-input__wrapper",n.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>`,o.insertAdjacentElement("afterend",n)),this.$el.addEventListener("input",(()=>{this.hideErrorForm()}),{passive:!0,once:!0}),null===(e=n.querySelector(".error-block-under-input"))||void 0===e||e.classList.remove("error-block-under-input--success");const s=n.querySelector(".error-block-under-input__secondary-text");s&&(s.textContent="");const i=parseFloat(n.style.height)||0,l=parseFloat(window.getComputedStyle(n).paddingTop)||0;i!==n.querySelector(".error-block-under-input").scrollHeight+16&&(n.style.height=`${i}px`,n.style.opacity="0",n.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 e.defaultParams={},e}();
|
|
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},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(".input"),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={};switch(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":const t=Object.fromEntries(new FormData(this.$el));s=JSON.stringify(t),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,"input-primary").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((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.js
CHANGED
|
@@ -38,6 +38,21 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
38
38
|
*
|
|
39
39
|
* @returns {string}
|
|
40
40
|
*/
|
|
41
|
+
function formatDate(dateValue, format) {
|
|
42
|
+
const date = new Date(dateValue);
|
|
43
|
+
/**
|
|
44
|
+
* Добавляет ведущие нули.
|
|
45
|
+
*
|
|
46
|
+
* @param {number} num
|
|
47
|
+
*
|
|
48
|
+
* @returns {string}
|
|
49
|
+
*/
|
|
50
|
+
const pad = (num) => num.toString().padStart(2, '0');
|
|
51
|
+
const day = pad(date.getDate());
|
|
52
|
+
const month = pad(date.getMonth() + 1);
|
|
53
|
+
const year = date.getFullYear().toString();
|
|
54
|
+
return format.replace('dd', day).replace('mm', month).replace('yyyy', year);
|
|
55
|
+
}
|
|
41
56
|
/**
|
|
42
57
|
* Находит родительский элемент по заданому селектору.
|
|
43
58
|
*
|
|
@@ -102,6 +117,70 @@ function isPhoneValid(value) {
|
|
|
102
117
|
return false;
|
|
103
118
|
return true;
|
|
104
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Кастомная сериализация формы в объект FormData.
|
|
122
|
+
*
|
|
123
|
+
* @param {HTMLElement} $element - DOM элемент для сериализации.
|
|
124
|
+
*
|
|
125
|
+
* @returns {FormData} Сериализованные данные формы в объекте FormData.
|
|
126
|
+
*/
|
|
127
|
+
function serializeToFormData($element) {
|
|
128
|
+
const elements = $element.tagName === 'FORM'
|
|
129
|
+
? Array.from($element.elements)
|
|
130
|
+
: Array.from($element.querySelectorAll('input, select, textarea, button'));
|
|
131
|
+
const data = new FormData();
|
|
132
|
+
elements.forEach(element => {
|
|
133
|
+
if (!(element instanceof HTMLInputElement ||
|
|
134
|
+
element instanceof HTMLSelectElement ||
|
|
135
|
+
element instanceof HTMLTextAreaElement ||
|
|
136
|
+
element instanceof HTMLButtonElement)) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!element.name || element.hasAttribute('data-no-serialize')) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const { name, type } = element;
|
|
143
|
+
if (type === 'file') {
|
|
144
|
+
if (element.getAttribute('multiple') === 'true') {
|
|
145
|
+
const files = element.files;
|
|
146
|
+
if (files) {
|
|
147
|
+
for (let i = 0; i < files.length; i++) {
|
|
148
|
+
// Добавляем каждый файл с уникальным ключом
|
|
149
|
+
data.append(`${name}[${i}]`, files[i]);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const files = element.files;
|
|
155
|
+
if (files && files[0])
|
|
156
|
+
data.append(name, files[0]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
let value;
|
|
161
|
+
if (type === 'tel') {
|
|
162
|
+
value = element.value
|
|
163
|
+
.split(/[\s()-]/)
|
|
164
|
+
.join('')
|
|
165
|
+
.replace(/^8/, '+7');
|
|
166
|
+
}
|
|
167
|
+
else if (type === 'checkbox' || type === 'radio') {
|
|
168
|
+
if (!element.checked)
|
|
169
|
+
return;
|
|
170
|
+
value = element.value;
|
|
171
|
+
}
|
|
172
|
+
else if (type === 'date') {
|
|
173
|
+
const format = element.getAttribute('data-date-format');
|
|
174
|
+
value = format ? formatDate(element.value, format) : element.value;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
value = element.value;
|
|
178
|
+
}
|
|
179
|
+
data.append(name, value);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return data;
|
|
183
|
+
}
|
|
105
184
|
/**
|
|
106
185
|
* Функция для разбора общих свойств ответа.
|
|
107
186
|
*
|
|
@@ -205,34 +284,30 @@ class Form {
|
|
|
205
284
|
const enctype = this.$el.getAttribute('enctype') || 'application/x-www-form-urlencoded';
|
|
206
285
|
let body = null;
|
|
207
286
|
let headers = {};
|
|
208
|
-
// Сбор данных из формы
|
|
209
|
-
const formData = new FormData(this.$el);
|
|
210
|
-
let data = {};
|
|
211
|
-
formData.forEach((value, key) => {
|
|
212
|
-
data[key] = value;
|
|
213
|
-
});
|
|
214
|
-
// Применение обёртки, если указано в настройках
|
|
215
|
-
if (typeof this.config.wrapData === 'function') {
|
|
216
|
-
data = this.config.wrapData(data);
|
|
217
|
-
}
|
|
218
287
|
switch (enctype) {
|
|
219
288
|
case 'application/x-www-form-urlencoded':
|
|
220
|
-
body = new URLSearchParams(
|
|
289
|
+
body = new URLSearchParams(new FormData(this.$el)).toString();
|
|
221
290
|
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
222
291
|
break;
|
|
223
292
|
case 'multipart/form-data':
|
|
224
|
-
body =
|
|
293
|
+
body = serializeToFormData(this.$el);
|
|
294
|
+
// ВАЖНО: Не указываем Content-Type, т.к. браузер сам добавит с корректной границей!
|
|
225
295
|
break;
|
|
226
296
|
case 'text/plain':
|
|
227
|
-
body =
|
|
297
|
+
body = Array.from(new FormData(this.$el))
|
|
228
298
|
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
|
229
299
|
.join('\n');
|
|
230
300
|
headers['Content-Type'] = 'text/plain';
|
|
231
301
|
break;
|
|
232
302
|
case 'application/json':
|
|
233
|
-
|
|
234
|
-
body = JSON.stringify(
|
|
303
|
+
const jsonData = Object.fromEntries(new FormData(this.$el));
|
|
304
|
+
body = JSON.stringify(jsonData);
|
|
235
305
|
headers['Content-Type'] = 'application/json';
|
|
306
|
+
break;
|
|
307
|
+
default:
|
|
308
|
+
console.warn(`Неизвестный enctype: ${enctype}. Используется application/x-www-form-urlencoded.`);
|
|
309
|
+
body = new URLSearchParams(new FormData(this.$el)).toString();
|
|
310
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
236
311
|
}
|
|
237
312
|
return fetch(action, {
|
|
238
313
|
method,
|
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
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "form-father",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Form Father: Библиотека для обработки форм",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rollup -c",
|
|
8
|
+
"watch": "rollup -c -w",
|
|
9
|
+
"release": "node scripts/release.js",
|
|
10
|
+
"demos": "BUILD_TARGET=demos npm run build && concurrently --kill-others \"vite\" \"npm run watch\""
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/poliklot/form-father.git"
|
|
15
|
+
},
|
|
7
16
|
"keywords": [
|
|
8
17
|
"form",
|
|
9
|
-
"
|
|
18
|
+
"vanila",
|
|
10
19
|
"javascript",
|
|
11
20
|
"typescript",
|
|
12
21
|
"validation",
|
|
@@ -14,11 +23,31 @@
|
|
|
14
23
|
],
|
|
15
24
|
"author": "Poliklot",
|
|
16
25
|
"license": "MIT",
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "https://github.com/poliklot/form-father.git"
|
|
20
|
-
},
|
|
21
26
|
"bugs": {
|
|
22
27
|
"url": "https://github.com/poliklot/form-father/issues"
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@babel/preset-env": "^7.26.0",
|
|
32
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
33
|
+
"@rollup/plugin-commonjs": "^28.0.1",
|
|
34
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
35
|
+
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
36
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
37
|
+
"chalk": "^5.3.0",
|
|
38
|
+
"concurrently": "^9.0.1",
|
|
39
|
+
"fs-extra": "^11.2.0",
|
|
40
|
+
"inquirer": "^12.1.0",
|
|
41
|
+
"ora": "^8.1.1",
|
|
42
|
+
"postcss-preset-env": "^10.0.8",
|
|
43
|
+
"prettier-plugin-jsdoc": "^1.3.0",
|
|
44
|
+
"rollup": "^4.24.3",
|
|
45
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
46
|
+
"rollup-plugin-delete": "^2.1.0",
|
|
47
|
+
"rollup-plugin-dts": "^6.1.1",
|
|
48
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
49
|
+
"sass-embedded": "^1.80.5",
|
|
50
|
+
"typescript": "^5.6.3",
|
|
51
|
+
"vite": "^5.4.10"
|
|
23
52
|
}
|
|
24
53
|
}
|