@metronlabs/rx-form-data
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -1,1 +0,1 @@ | ||
"use strict";const e=e=>"string"==typeof e,t=t=>Boolean(e(t)&&t.trim().length),n=e=>"[object RegExp]"===Object.prototype.toString.call(e),r={_is:"None"};function a(e){return{_is:"Some",value:e}}function c(e){return"Some"===e._is}function i(e){return"None"===e._is}function s(e,t){return n=>i(n)?e():t(n.value)}function o(e,t,n){return i(e)&&i(t)?r:c(e)&&c(t)?n?a(n(e.value,t.value)):t:c(e)&&i(t)?e:i(e)&&c(t)?t:r}function u(e){return null===e||void 0===e?r:a(e)}function l(e){return isNaN(Number(e))?r:a(Number(e))}function E(n,c){return e(n)?c?t(n)?a(n):r:a(n):r}const f={INPUT_TEXT:"input:text",INPUT_NUMBER:"input:number",INPUT_EMAIL:"input:email",INPUT_PASSWORD:"input:password",INPUT_CHECKBOX:"input:checkbox",INPUT_RADIO:"input:radio",INPUT_COLOR:"input:color",INPUT_DATE:"input:date",INPUT_DATETIME_LOCAL:"input:datetime-local",INPUT_FILE:"input:file",INPUT_HIDDEN:"input:hidden",INPUT_MONTH:"input:month",INPUT_RANGE:"input:range",INPUT_SEARCH:"input:search",INPUT_TEL:"input:tel",INPUT_TIME:"input:time",INPUT_URL:"input:url",INPUT_WEEK:"input:week",TEXTAREA:"textarea:textarea",SELECT_SINGLE:"select:select-one",SELECT_MULTIPLE:"select:select-multiple"},T={FOCUS:"focus",INPUT:"input",CHANGE:"change",BLUR:"blur",SUBMIT:"submit",RESET:"reset"},m="REGISTER_ALL",d="UNREGISTER_ALL",I="REGISTER",N="UNREGISTER",_="UPSERT_FIELD",R="DELETE_FIELD",U="CLEAR_FIELDS",v="RESET",L={EMIT_FORM_VALUES:"EMIT_FORM_VALUES"},A="ADD",S="DELETE",b="CLEAR",p={REGISTER:"REGISTER_FIELDS",REGISTER_ALL:"REGISTER_ALL_FIELDS",UNREGISTER:"UNREGISTER_FIELDS",UNREGISTER_ALL:"UNREGISTER_ALL_FIELDS",DESTROY:"DESTROY_PROGRAM"};function P(e){return e instanceof HTMLFormElement}function O(e){return e instanceof HTMLInputElement}function y(e){return e instanceof HTMLTextAreaElement}function h(e){return e instanceof HTMLSelectElement}function w(e){return O(e)||h(e)||y(e)}function D(e){return w(e)?O(e)?function(e){if(!O(e))return r;const n=`${e.tagName.toLowerCase()}:${e.type}`;switch(n){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:return a(e.value.trim());case f.INPUT_PASSWORD:return a(e.value);case f.INPUT_NUMBER:case f.INPUT_RANGE:return l(Number(e.value.trim()));case f.INPUT_URL:try{return a(new URL(e.value.trim()).href.trim())}catch(t){return console.warn("[RxFormData] Failed to decode url input field value into URL object",e.value,t),r}case f.INPUT_TEL:return a(e.value.trim().replace(/\D/g,""));case f.INPUT_FILE:return s(()=>r,e=>a(Object.freeze(Array.from(Array(e.length).keys()).reduce((t,n)=>{const r=e.item(n);return r?t.concat(r):t},[]))))(u(e.files));case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:return l(e.valueAsNumber);case f.INPUT_MONTH:try{return a(new Date(e.value+"-1").getTime())}catch(e){return console.error("[RxFormData] Failed to decode month input field value into number",e),r}case f.INPUT_RADIO:case f.INPUT_CHECKBOX:{const c=n.split(":")[1],s=u(e.form);if(i(s))return r;const o=s.value.querySelectorAll(`input[type='${c}'][name='${e.name}']:checked`);return a(Object.freeze(Array.from(o).map((n,r)=>O(n)&&t(n.value)?n.value.trim():`${e.name}[${r}]`)))}default:return r}}(e):h(e)?function(e){if(!h(e))return r;switch(`${e.tagName.toLowerCase()}:${e.type}`){case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return a(Object.freeze(Array.from(e.selectedOptions).map((n,r)=>t(n.value)?n.value.trim():`${e.name}[${r}]`)));default:return r}}(e):y(e)?function(e){return y(e)?a(e.value.trim()):r}(e):r:r}function g(t){return!!e(t)||("number"==typeof t||!(!Array.isArray(t)||!t.every(e)&&!t.every(e=>e instanceof File)))}function M(e){return t(e)&&Object.keys(f).includes(e)}function C(e){if(e instanceof Error)throw e;const t=new Error("[RxFormData] ERROR!");throw t.details=JSON.stringify(e),t}function j(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&"Object"===e.constructor.name}const F=Object.freeze({$:r,tag:r,name:r,value:r,validity:r,touched:!1,modified:!1,visited:!1});function k(e){if(!j(e))return!1;const n=Object.keys(F);if(!Object.keys(e).every(e=>n.includes(e)))return!1;const r=(e,n)=>j(e)&&t(e._is)&&["none","some"].includes(e._is)&&("some"!==e._is||n(e.value));return Object.entries(e).reduce((e,[n,a])=>{switch(n){case"$":return e&&r(a,w);case"tag":return e&&r(a,M);case"name":return e&&r(a,t);case"value":return e&&r(a,g);case"validity":return e&&r(a,e=>e instanceof ValidityState);case"touched":case"visited":case"modified":return"boolean"==typeof a;default:return!1}},!0)}function G(e,t){const n=s(()=>t,e=>e)(e.$),r=s(()=>t,e=>e)(e.tag),a=s(()=>t,e=>e)(e.name),c=s(()=>t,e=>e)(e.validity);return Object.freeze({$:n,tag:r,name:a,value:(()=>{if(r===t)return t;const n=s(()=>t,e=>e)(e.value);if(n===t)return n;switch(r){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:case f.TEXTAREA:case f.INPUT_URL:case f.INPUT_TEL:case f.INPUT_PASSWORD:return String(n);case f.INPUT_NUMBER:case f.INPUT_RANGE:case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:case f.INPUT_MONTH:return Number(n);case f.INPUT_FILE:return Array.isArray(n)?Object.freeze(n.map(e=>Object.freeze(e))):[];case f.INPUT_RADIO:case f.INPUT_CHECKBOX:case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return Array.isArray(n)?Object.freeze(n.map(String)):[];default:return t}})(),validity:c,touched:e.touched,modified:e.modified,visited:e.visited})}function $(e,t){if(i(t.name))return e;const n=t.name.value,r=u(e.get(n)),a=s(()=>t,e=>{return n=e,r=t,Object.freeze({$:o(n.$,r.$),tag:o(n.tag,r.tag),name:o(n.name,r.name),value:o(n.value,r.value),validity:o(n.validity,r.validity,(e,t)=>({...e,...t})),touched:n.touched||r.touched,modified:n.modified||r.modified,visited:n.visited||r.visited});var n,r})(r);return e.set(n,a)}function z(e,t){return e.clear(),t?new Map(t.entries()):e}function H(e,n,r){for(let e=0,t=r.length;e<t;e++)n.delete(r[e]);for(const n of e.keys()){r.some(e=>e instanceof RegExp?e.test(n):!!t(e)&&e.trim()===n.trim())&&e.delete(n)}return[n,e]}function x(e,t){const n=new CustomEvent(L.EMIT_FORM_VALUES,{detail:Object.freeze(new Map(t.entries()))});e.dispatchEvent(n)}function B(r){const a=new Map;if(i(r))return void C("[RxFormData] invalid form element for form field storage initialization");const c=r.value,o=new Map;o.set(a,new Map(a.entries()));const u=()=>{const e=o.get(a);return e?new Map(e.entries()):new Map},l=new Set,f=(new Map).set(l,l),T=()=>{const e=f.get(l);return e?new Set(e.values()):new Set};return{storage:u,action:(r,L)=>{switch(r){case _:if(k(L)){const e=s(()=>"",e=>e.trim())(L.name);[...T().keys()].some(r=>t(r)?r.trim()===e.trim():!!n(r)&&r.test(e))&&(o.set(a,$(u(),L)),x(c,u()))}break;case U:o.set(a,z(u())),f.set(l,new Set),x(c,u());break;case m:{const e=Array.from(c.elements).reduce((e,t)=>w(t)?e.concat(t.name):e,[]);f.set(l,new Set(e));break}case d:f.set(l,new Set);break;case R:{const n=Array.isArray(L)?L.filter(e=>t(e)||k(e)):[];n.length&&(o.set(a,function(n,r){return r.reduce((n,r)=>{const a=e(r)?E(r,!0):r.name;return i(a)?n:t(a.value)?(n.delete(a.value.trim()),n):n},n)}(u(),n)),x(c,u()));break}case v:o.set(a,z(u(),a)),x(c,u());break;case I:{const e=Array.isArray(L)?L.filter(e=>t(e)||n(e)):[];e.length&&f.set(l,function(e,t){for(let n=0,r=t.length;n<r;n++)e.add(t[n]);return e}(T(),e));break}case N:if(L&&j(L)){const e=Array.isArray(L.use)?L.use.filter(e=>t(e)||n(e)):[];if(e.length){const t=H(u(),T(),e);f.set(l,t[0]),L.keepvalues||(o.set(a,t[1]),x(c,u()))}}else{const e=Array.isArray(L)?L.filter(e=>t(e)||n(e)):[];if(e.length){const t=H(u(),T(),e);f.set(l,t[0])}}}}}}function X(e,t){t(_,function(e){const t=u(e.target);if(i(t))return F;if(!w(t.value))return F;const n=t.value,r=E(n.name,!0),c=a(`${n.tagName}:${n.type}`.toLowerCase()),s=D(n),o=[T.CHANGE,T.BLUR].includes(e.type),l=[T.CHANGE].includes(e.type),f=[T.FOCUS,T.BLUR].includes(e.type);return Object.freeze({$:a(n),name:r,tag:c,value:s,validity:a(Object.freeze(n.validity)),touched:o,modified:l,visited:f})}(e))}function K(e,t,n,r){return function(a){if(a instanceof CustomEvent)switch(a.type){case L.EMIT_FORM_VALUES:{const e=r.subscribers(),t=null,a=[...n.storage().entries()].reduce((e,[n,r])=>(e[n]=G(r,t),e),{});for(const t of e)t(a);break}}else switch(a.type){case T.SUBMIT:a.preventDefault(),async function(e,t,n){const r=new FormData(e);new Promise((a,c)=>{Promise.resolve().then(()=>{const e=[...t.entries()].reduce((e,[t,n])=>(e[t]=G(n,null),e),{});return Promise.resolve(n(Object.freeze(e),r))}).then(()=>{console.info(`[RxFormData #${e.id}] form submission handler success`),a()}).catch(t=>{console.error(`[RxFormData #${e.id}] form submission handler error(s)`,t),c(t)})})}(e,n.storage(),t);break;case T.FOCUS:case T.INPUT:case T.CHANGE:case T.BLUR:X(a,n.action);break;case T.RESET:n.action(v)}}}module.exports=function(e,c){const s=function(e){if(P(e))return a(e);if(i(E(e,!0)))return r;const t=u(document.querySelector("form#"+e.trim()));return i(t)?r:P(t.value)?a(t.value):r}(e);if(i(s))return void C("Invalid form element. Form id provided did not match any form element in the DOM.");const o=B(s)||null,l=o?function(e,t,n){const r=new Set;if(i(e))return void C("[RxFormData] invalid form element for events initialization");const a=new Map;a.set(r,new Set(r.values()));const c=()=>{const e=a.get(r);return e||new Set},s=(e,t)=>{switch(e){case A:t instanceof Function&&a.set(r,new Set(c().values()).add(t));break;case S:if(t instanceof Function){const e=new Set(c().values());e.delete(t),a.set(r,e)}break;case b:a.set(r,new Set)}},o={subscribers:c,action:s},u=e.value,l=K(u,t,n,o);return[...Object.values(T),...Object.values(L)].forEach(e=>{u.addEventListener(e,l,!0)}),{...o,cleanup:()=>{[...Object.values(T),...Object.values(L)].forEach(e=>{u.removeEventListener(e,l,!0)}),s(b),n.action(U)}}}(s,c,o):null;return o&&l?Object.freeze({ACTION_TYPE:Object.freeze(p),register:Object.freeze(e=>(o.action(I,e),Object.freeze(()=>{o.action(N,e)}))),subscribe:Object.freeze(e=>(l.action(A,e),Object.freeze(()=>{l.action(S,e)}))),dispatch:Object.freeze((r,a)=>{switch(r){case p.REGISTER_ALL:o.action(m);break;case p.REGISTER:{const e=Array.isArray(a)?a.reduce((e,r)=>t(r)||n(r)?e.concat(r):e,[]):[];e.length&&o.action(I,e);break}case p.UNREGISTER_ALL:o.action(d),!(!1!==a)&&o.action(v);break;case p.UNREGISTER:{const e=Array.isArray(a)?a.reduce((e,r)=>t(r)||n(r)?e.concat(r):e,[]):[];e.length&&o.action(N,e);break}case p.DESTROY:o.action(v),o.action(d),l.cleanup&&l.cleanup();break;default:return void console.debug(`[RxFormData: #${e}] uknown action dispatched...`,a)}})}):void 0}; | ||
"use strict";const e=e=>"string"==typeof e,t=t=>Boolean(e(t)&&t.trim().length),r=e=>"[object RegExp]"===Object.prototype.toString.call(e),n={_is:"None"};function a(e){return{_is:"Some",value:e}}function s(e){return"Some"===e._is}function c(e){return"None"===e._is}function i(e,t){return r=>c(r)?e():t(r.value)}function o(e,t,r){return c(e)&&c(t)?n:s(e)&&s(t)?r?a(r(e.value,t.value)):t:s(e)&&c(t)?e:c(e)&&s(t)?t:n}function u(e){return null===e||void 0===e?n:a(e)}function l(e){return isNaN(Number(e))?n:a(Number(e))}function E(r,s){return e(r)?s?t(r)?a(r):n:a(r):n}const f={INPUT_TEXT:"input:text",INPUT_NUMBER:"input:number",INPUT_EMAIL:"input:email",INPUT_PASSWORD:"input:password",INPUT_CHECKBOX:"input:checkbox",INPUT_RADIO:"input:radio",INPUT_COLOR:"input:color",INPUT_DATE:"input:date",INPUT_DATETIME_LOCAL:"input:datetime-local",INPUT_FILE:"input:file",INPUT_HIDDEN:"input:hidden",INPUT_MONTH:"input:month",INPUT_RANGE:"input:range",INPUT_SEARCH:"input:search",INPUT_TEL:"input:tel",INPUT_TIME:"input:time",INPUT_URL:"input:url",INPUT_WEEK:"input:week",TEXTAREA:"textarea:textarea",SELECT_SINGLE:"select:select-one",SELECT_MULTIPLE:"select:select-multiple"},m={FOCUS:"focus",INPUT:"input",CHANGE:"change",BLUR:"blur",SUBMIT:"submit",RESET:"reset"},d="REGISTER_ALL",T="UNREGISTER_ALL",I="REGISTER",R="UNREGISTER",_="UPSERT_FIELD",A="DELETE_FIELD",v="CLEAR_FIELDS",N="RESET",O="UPSERT_DECODER",U="REMOVE_DECODER",S="CLEAR_DECODERS",y={EMIT_FORM_VALUES:"EMIT_FORM_VALUES"},L="ADD",b="DELETE",p="CLEAR",D={REGISTER:"REGISTER_FIELDS",REGISTER_ALL:"REGISTER_ALL_FIELDS",UNREGISTER:"UNREGISTER_FIELDS",UNREGISTER_ALL:"UNREGISTER_ALL_FIELDS",ADD_DECODERS:"ADD_DECODERS",REMOVE_DECODERS:"REMOVE_DECODERS",CLEAR_DECODERS:"CLEAR_DECODERS",DESTROY:"DESTROY_PROGRAM"};function P(e){return e instanceof HTMLFormElement}function h(e){return e instanceof HTMLInputElement}function g(e){return e instanceof HTMLTextAreaElement}function w(e){return e instanceof HTMLSelectElement}function M(e){return h(e)||w(e)||g(e)}function C(e){return M(e)?h(e)?function(e){if(!h(e))return n;const r=`${e.tagName.toLowerCase()}:${e.type}`;switch(r){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:return a(e.value.trim());case f.INPUT_PASSWORD:return a(e.value);case f.INPUT_NUMBER:case f.INPUT_RANGE:return l(Number(e.value.trim()));case f.INPUT_URL:try{return a(new URL(e.value.trim()).href.trim())}catch(t){return console.warn("[RxFormData] Failed to decode url input field value into URL object",e.value,t),n}case f.INPUT_TEL:return a(e.value.trim().replace(/\D/g,""));case f.INPUT_FILE:return i(()=>n,e=>a(Object.freeze(Array.from(Array(e.length).keys()).reduce((t,r)=>{const n=e.item(r);return n?t.concat(n):t},[]))))(u(e.files));case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:return l(e.valueAsNumber);case f.INPUT_MONTH:try{return a(new Date(e.value+"-1").getTime())}catch(e){return console.error("[RxFormData] Failed to decode month input field value into number",e),n}case f.INPUT_RADIO:case f.INPUT_CHECKBOX:{const s=r.split(":")[1],i=u(e.form);if(c(i))return n;const o=i.value.querySelectorAll(`input[type='${s}'][name='${e.name}']:checked`);return a(Object.freeze(Array.from(o).map((r,n)=>h(r)&&t(r.value)?r.value.trim():`${e.name}[${n}]`)))}default:return n}}(e):w(e)?function(e){if(!w(e))return n;switch(`${e.tagName.toLowerCase()}:${e.type}`){case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return a(Object.freeze(Array.from(e.selectedOptions).map((r,n)=>t(r.value)?r.value.trim():`${e.name}[${n}]`)));default:return n}}(e):g(e)?function(e){return g(e)?a(e.value.trim()):n}(e):n:n}function j(t){return!!e(t)||("number"==typeof t||!(!Array.isArray(t)||!t.every(e)&&!t.every(e=>e instanceof File)))}function F(e){return t(e)&&Object.keys(f).includes(e)}function k(n){return e(n)?t(n.trim()):r(n)}function z(e){if(e instanceof Error)throw e;const t=new Error("[RxFormData] ERROR!");throw t.details=JSON.stringify(e),t}function G(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&"Object"===e.constructor.name}const $=Object.freeze({$:n,tag:n,name:n,value:n,validity:a(Object.freeze({badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:!1,valueMissing:!1})),touched:!1,modified:!1,visited:!1});function H(e){if(!G(e))return!1;const r=Object.keys($);if(!Object.keys(e).every(e=>r.includes(e)))return!1;const n=(e,r)=>G(e)&&t(e._is)&&["none","some"].includes(e._is)&&("some"!==e._is||r(e.value));return Object.entries(e).reduce((e,[r,a])=>{switch(r){case"$":return e&&n(a,M);case"tag":return e&&n(a,F);case"name":return e&&n(a,t);case"value":return e&&n(a,j);case"validity":return e&&n(a,e=>G(e)||e instanceof ValidityState);case"touched":case"visited":case"modified":return"boolean"==typeof a;default:return!1}},!0)}function x(e,t){const r=i(()=>t,e=>e)(e.$),n=i(()=>t,e=>e)(e.tag),a=i(()=>t,e=>e)(e.name),s=i(()=>t,e=>e)(e.validity);return Object.freeze({$:r,tag:n,name:a,value:(()=>{if(n===t)return t;const r=i(()=>t,e=>e)(e.value);if(r===t)return r;switch(n){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:case f.TEXTAREA:case f.INPUT_URL:case f.INPUT_TEL:case f.INPUT_PASSWORD:return String(r);case f.INPUT_NUMBER:case f.INPUT_RANGE:case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:case f.INPUT_MONTH:return Number(r);case f.INPUT_FILE:return Array.isArray(r)?Object.freeze(r.map(e=>Object.freeze(e))):[];case f.INPUT_RADIO:case f.INPUT_CHECKBOX:case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return Array.isArray(r)?Object.freeze(r.map(String)):[];default:return t}})(),validity:s,touched:e.touched,modified:e.modified,visited:e.visited})}function B(e){if(!G(e))return n;if(!t(e.name))return n;if(!Array.isArray(e.use))return n;if(!e.use.every(e=>e instanceof Function))return n;if(!(Array.isArray(e.messages)&&e.messages.every(t)||e.messages instanceof Function))return n;return a({name:e.name.trim(),input:[],use:e.use,messages:Array.isArray(e.messages)?()=>e.messages:e.messages})}function V(e){return s(B(e))}async function X(e,r){return new Promise(n=>{Promise.resolve().then(()=>Promise.all(e.use.map(e=>e(r)))).then(t=>t.every(e=>!0===e)?Promise.resolve([]):Promise.resolve(e.messages({inputs:r,outputs:t}))).then(r=>{Array.isArray(r)?r.length?n({decoder:e.name,success:!1,errors:r.filter(t)}):n({decoder:e.name,success:!0,errors:[]}):t(r)?n({decoder:e.name,success:!1,errors:[r]}):n({decoder:e.name,success:!1,errors:["Decoder error(s): "+JSON.stringify(r)]})}).catch(t=>{console.error("[RxFormData] An error occured while running decoder resolvers",e,t),n({decoder:e.name,success:!1,errors:["Decoder implementation error(s)"]})})})}function K(e,t){if(c(t.name))return e;const r=t.name.value,n=u(e.get(r)),a=i(()=>t,e=>{return r=e,n=t,Object.freeze({$:o(r.$,n.$),tag:o(r.tag,n.tag),name:o(r.name,n.name),value:o(r.value,n.value),validity:o(r.validity,n.validity),touched:r.touched||n.touched,modified:r.modified||n.modified,visited:r.visited||n.visited});var r,n})(n);return e.set(r,a)}function W(e,t){return e.clear(),t?new Map(t.entries()):e}function Y(e,r,n){for(let e=0,t=n.length;e<t;e++)r.delete(n[e]);for(const r of e.keys()){n.some(e=>e instanceof RegExp?e.test(r):!!t(e)&&e.trim()===r.trim())&&e.delete(r)}return[r,e]}function q(e,t){const r=new CustomEvent(y.EMIT_FORM_VALUES,{detail:Object.freeze(new Map(t.entries()))});e.dispatchEvent(r)}function J(n){const a=new Map;if(c(n))return void z("[RxFormData] invalid form element for form field storage initialization");const s=n.value,o=new Map;o.set(a,new Map(a.entries()));const u=()=>{const e=o.get(a);return e?new Map(e.entries()):new Map},l=new Set,f=(new Map).set(l,l),m=()=>{const e=f.get(l);return e?new Set(e.values()):new Set},y=new Map,L=(new Map).set(y,y),b=()=>{const e=L.get(y);return e?new Map(e.entries()):new Map};return{storage:u,decoders:b,action:(n,p)=>{switch(n){case _:if(H(p)){const e=i(()=>"",e=>e.trim())(p.name);[...m().keys()].some(n=>t(n)?n.trim()===e.trim():!!r(n)&&n.test(e))&&(o.set(a,K(u(),p)),q(s,u()))}break;case v:o.set(a,W(u())),f.set(l,new Set),L.set(y,new Map),q(s,u());break;case d:{const e=Array.from(s.elements).reduce((e,t)=>M(t)?e.concat(t.name):e,[]);f.set(l,new Set(e));break}case T:f.set(l,new Set);break;case A:{const r=Array.isArray(p)?p.filter(e=>t(e)||H(e)):[];r.length&&(o.set(a,function(r,n){return n.reduce((r,n)=>{const a=e(n)?E(n,!0):n.name;return c(a)?r:t(a.value)?(r.delete(a.value.trim()),r):r},r)}(u(),r)),q(s,u()));break}case N:o.set(a,W(u(),a)),q(s,u());break;case I:{const e=Array.isArray(p)?p.filter(e=>t(e)||r(e)):[];e.length&&f.set(l,function(e,t){for(let r=0,n=t.length;r<n;r++)e.add(t[r]);return e}(m(),e));break}case R:if(p&&G(p)){const e=Array.isArray(p.use)?p.use.filter(e=>t(e)||r(e)):[];if(e.length){const t=Y(u(),m(),e);f.set(l,t[0]),p.keepvalues||(o.set(a,t[1]),q(s,u()))}}else{const e=Array.isArray(p)?p.filter(e=>t(e)||r(e)):[];if(e.length){const t=Y(u(),m(),e);f.set(l,t[0])}}break;case O:if(Array.isArray(p)&&p.every(V)){const e=b();for(let t=0,r=p.length;t<r;t++){const r=p[t];e.set(r.name,r)}L.set(y,e)}break;case U:if(Array.isArray(p)){const e=b();for(let n=0,a=p.length;n<a;n++){const a=p[n];if(k(a))for(const[n]of e)(t(a)&&a===n||r(a)&&a.test(n))&&e.delete(n)}L.set(y,e)}break;case S:L.set(y,new Map)}}}}function Q(e,t){t(_,function(e){const t=u(e.target);if(c(t))return $;if(!M(t.value))return $;const r=t.value,n=E(r.name,!0),s=a(`${r.tagName}:${r.type}`.toLowerCase()),i=C(r),o=[m.CHANGE,m.BLUR].includes(e.type),l=[m.CHANGE].includes(e.type),f=[m.FOCUS,m.BLUR].includes(e.type);return Object.freeze({$:a(r),name:n,tag:s,value:i,validity:a(Object.freeze(r.validity)),touched:o,modified:l,visited:f})}(e))}function Z(e,t,r,n){return function(a){if(a instanceof CustomEvent)switch(a.type){case y.EMIT_FORM_VALUES:{const e=n.subscribers(),t=null,a=Object.freeze([...r.storage().entries()].reduce((e,[r,n])=>(e[r]=x(n,t),e),{}));Promise.all([...r.decoders().values()].map(e=>X(e,a))).then(t=>{const r=t.reduce((e,t)=>(e[t.decoder]=Object.freeze(t),e),{});for(const t of e)t(a,Object.freeze(r))}).catch(t=>{const r=new Error("[RxFormData] An an error occured while running decoders. Check the error details for more info.");r.details=t;for(const t of e)t(a,r)});break}}else switch(a.type){case m.SUBMIT:a.preventDefault(),async function(e,t,r,n){const a=new FormData(e);new Promise((s,c)=>{Promise.resolve().then(()=>{const e=[...t.entries()].reduce((e,[t,r])=>(e[t]=x(r,null),e),{});return Promise.all([null,e,Promise.all(Array.from(r.values()).map(t=>X(t,e)))])}).then(([e,t,r])=>{const s=r.reduce((e,t)=>Object.assign({},e,Object.freeze(t)),{});return Promise.resolve(n(Object.freeze(t),Object.freeze(s),a))}).then(()=>{console.info(`[RxFormData #${e.id}] form submission handler success`),s()}).catch(t=>{console.error(`[RxFormData #${e.id}] form submission handler error(s)`,t),c(t)})})}(e,r.storage(),r.decoders(),t);break;case m.FOCUS:case m.INPUT:case m.CHANGE:case m.BLUR:Q(a,r.action);break;case m.RESET:r.action(N)}}}module.exports=function(e,i){const o=function(e){if(P(e))return a(e);if(c(E(e,!0)))return n;const t=u(document.querySelector("form#"+e.trim()));return c(t)?n:P(t.value)?a(t.value):n}(e);if(c(o))return void z("Invalid form element. Form id provided did not match any form element in the DOM.");const l=J(o)||null,f=l?function(e,t,r){const n=new Set;if(c(e))return void z("[RxFormData] invalid form element for events initialization");const a=new Map;a.set(n,new Set(n.values()));const s=()=>{const e=a.get(n);return e||new Set},i=(e,t)=>{switch(e){case L:t instanceof Function&&a.set(n,new Set(s().values()).add(t));break;case b:if(t instanceof Function){const e=new Set(s().values());e.delete(t),a.set(n,e)}break;case p:a.set(n,new Set)}},o={subscribers:s,action:i},u=e.value,l=Z(u,t,r,o);return[...Object.values(m),...Object.values(y)].forEach(e=>{u.addEventListener(e,l,!0)}),{...o,cleanup:()=>{[...Object.values(m),...Object.values(y)].forEach(e=>{u.removeEventListener(e,l,!0)}),i(p),r.action(v)}}}(o,i,l):null;return l&&f?Object.freeze({ACTION_TYPE:Object.freeze(D),register:Object.freeze(e=>(l.action(I,e),Object.freeze(()=>{l.action(R,e)}))),subscribe:Object.freeze(e=>(f.action(L,e),Object.freeze(()=>{f.action(b,e)}))),dispatch:Object.freeze((n,a)=>{switch(n){case D.REGISTER_ALL:l.action(d);break;case D.REGISTER:{const e=Array.isArray(a)?a.reduce((e,n)=>t(n)||r(n)?e.concat(n):e,[]):[];e.length&&l.action(I,e);break}case D.UNREGISTER_ALL:l.action(T),!(!1!==a)&&l.action(N);break;case D.UNREGISTER:{const e=Array.isArray(a)?a.reduce((e,n)=>t(n)||r(n)?e.concat(n):e,[]):[];e.length&&l.action(R,e);break}case D.DESTROY:l.action(N),l.action(T),l.action(S),f.cleanup&&f.cleanup();break;case D.ADD_DECODERS:if(Array.isArray(a)){const e=a.reduce((e,t)=>{const r=B(t);return s(r)?e.concat(r.value):e},[]);e.length&&l.action(O,e)}break;case D.REMOVE_DECODERS:Array.isArray(a)&&l.action(U,a.filter(k));break;case D.CLEAR_DECODERS:l.action(S);break;default:return void console.debug(`[RxFormData: #${e}] uknown action dispatched...`,a)}})}):void 0}; |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).RxFormData=t()}(this,(function(){"use strict";const e=e=>"string"==typeof e,t=t=>Boolean(e(t)&&t.trim().length),n=e=>"[object RegExp]"===Object.prototype.toString.call(e),r={_is:"None"};function a(e){return{_is:"Some",value:e}}function c(e){return"Some"===e._is}function i(e){return"None"===e._is}function s(e,t){return n=>i(n)?e():t(n.value)}function o(e,t,n){return i(e)&&i(t)?r:c(e)&&c(t)?n?a(n(e.value,t.value)):t:c(e)&&i(t)?e:i(e)&&c(t)?t:r}function u(e){return null===e||void 0===e?r:a(e)}function l(e){return isNaN(Number(e))?r:a(Number(e))}function f(n,c){return e(n)?c?t(n)?a(n):r:a(n):r}const E={INPUT_TEXT:"input:text",INPUT_NUMBER:"input:number",INPUT_EMAIL:"input:email",INPUT_PASSWORD:"input:password",INPUT_CHECKBOX:"input:checkbox",INPUT_RADIO:"input:radio",INPUT_COLOR:"input:color",INPUT_DATE:"input:date",INPUT_DATETIME_LOCAL:"input:datetime-local",INPUT_FILE:"input:file",INPUT_HIDDEN:"input:hidden",INPUT_MONTH:"input:month",INPUT_RANGE:"input:range",INPUT_SEARCH:"input:search",INPUT_TEL:"input:tel",INPUT_TIME:"input:time",INPUT_URL:"input:url",INPUT_WEEK:"input:week",TEXTAREA:"textarea:textarea",SELECT_SINGLE:"select:select-one",SELECT_MULTIPLE:"select:select-multiple"},T={FOCUS:"focus",INPUT:"input",CHANGE:"change",BLUR:"blur",SUBMIT:"submit",RESET:"reset"},d="REGISTER_ALL",m="UNREGISTER_ALL",I="REGISTER",N="UNREGISTER",_="UPSERT_FIELD",R="DELETE_FIELD",U="CLEAR_FIELDS",v="RESET",L={EMIT_FORM_VALUES:"EMIT_FORM_VALUES"},A="ADD",S="DELETE",b="CLEAR",p={REGISTER:"REGISTER_FIELDS",REGISTER_ALL:"REGISTER_ALL_FIELDS",UNREGISTER:"UNREGISTER_FIELDS",UNREGISTER_ALL:"UNREGISTER_ALL_FIELDS",DESTROY:"DESTROY_PROGRAM"};function y(e){return e instanceof HTMLFormElement}function P(e){return e instanceof HTMLInputElement}function O(e){return e instanceof HTMLTextAreaElement}function h(e){return e instanceof HTMLSelectElement}function D(e){return P(e)||h(e)||O(e)}function w(e){return D(e)?P(e)?function(e){if(!P(e))return r;const n=`${e.tagName.toLowerCase()}:${e.type}`;switch(n){case E.INPUT_TEXT:case E.INPUT_SEARCH:case E.INPUT_EMAIL:case E.INPUT_COLOR:case E.INPUT_HIDDEN:return a(e.value.trim());case E.INPUT_PASSWORD:return a(e.value);case E.INPUT_NUMBER:case E.INPUT_RANGE:return l(Number(e.value.trim()));case E.INPUT_URL:try{return a(new URL(e.value.trim()).href.trim())}catch(t){return console.warn("[RxFormData] Failed to decode url input field value into URL object",e.value,t),r}case E.INPUT_TEL:return a(e.value.trim().replace(/\D/g,""));case E.INPUT_FILE:return s(()=>r,e=>a(Object.freeze(Array.from(Array(e.length).keys()).reduce((t,n)=>{const r=e.item(n);return r?t.concat(r):t},[]))))(u(e.files));case E.INPUT_DATE:case E.INPUT_DATETIME_LOCAL:case E.INPUT_TIME:case E.INPUT_WEEK:return l(e.valueAsNumber);case E.INPUT_MONTH:try{return a(new Date(e.value+"-1").getTime())}catch(e){return console.error("[RxFormData] Failed to decode month input field value into number",e),r}case E.INPUT_RADIO:case E.INPUT_CHECKBOX:{const c=n.split(":")[1],s=u(e.form);if(i(s))return r;const o=s.value.querySelectorAll(`input[type='${c}'][name='${e.name}']:checked`);return a(Object.freeze(Array.from(o).map((n,r)=>P(n)&&t(n.value)?n.value.trim():`${e.name}[${r}]`)))}default:return r}}(e):h(e)?function(e){if(!h(e))return r;switch(`${e.tagName.toLowerCase()}:${e.type}`){case E.SELECT_SINGLE:case E.SELECT_MULTIPLE:return a(Object.freeze(Array.from(e.selectedOptions).map((n,r)=>t(n.value)?n.value.trim():`${e.name}[${r}]`)));default:return r}}(e):O(e)?function(e){return O(e)?a(e.value.trim()):r}(e):r:r}function g(t){return!!e(t)||("number"==typeof t||!(!Array.isArray(t)||!t.every(e)&&!t.every(e=>e instanceof File)))}function M(e){return t(e)&&Object.keys(E).includes(e)}function C(e){if(e instanceof Error)throw e;const t=new Error("[RxFormData] ERROR!");throw t.details=JSON.stringify(e),t}function j(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&"Object"===e.constructor.name}const F=Object.freeze({$:r,tag:r,name:r,value:r,validity:r,touched:!1,modified:!1,visited:!1});function k(e){if(!j(e))return!1;const n=Object.keys(F);if(!Object.keys(e).every(e=>n.includes(e)))return!1;const r=(e,n)=>j(e)&&t(e._is)&&["none","some"].includes(e._is)&&("some"!==e._is||n(e.value));return Object.entries(e).reduce((e,[n,a])=>{switch(n){case"$":return e&&r(a,D);case"tag":return e&&r(a,M);case"name":return e&&r(a,t);case"value":return e&&r(a,g);case"validity":return e&&r(a,e=>e instanceof ValidityState);case"touched":case"visited":case"modified":return"boolean"==typeof a;default:return!1}},!0)}function G(e,t){const n=s(()=>t,e=>e)(e.$),r=s(()=>t,e=>e)(e.tag),a=s(()=>t,e=>e)(e.name),c=s(()=>t,e=>e)(e.validity);return Object.freeze({$:n,tag:r,name:a,value:(()=>{if(r===t)return t;const n=s(()=>t,e=>e)(e.value);if(n===t)return n;switch(r){case E.INPUT_TEXT:case E.INPUT_SEARCH:case E.INPUT_EMAIL:case E.INPUT_COLOR:case E.INPUT_HIDDEN:case E.TEXTAREA:case E.INPUT_URL:case E.INPUT_TEL:case E.INPUT_PASSWORD:return String(n);case E.INPUT_NUMBER:case E.INPUT_RANGE:case E.INPUT_DATE:case E.INPUT_DATETIME_LOCAL:case E.INPUT_TIME:case E.INPUT_WEEK:case E.INPUT_MONTH:return Number(n);case E.INPUT_FILE:return Array.isArray(n)?Object.freeze(n.map(e=>Object.freeze(e))):[];case E.INPUT_RADIO:case E.INPUT_CHECKBOX:case E.SELECT_SINGLE:case E.SELECT_MULTIPLE:return Array.isArray(n)?Object.freeze(n.map(String)):[];default:return t}})(),validity:c,touched:e.touched,modified:e.modified,visited:e.visited})}function $(e,t){if(i(t.name))return e;const n=t.name.value,r=u(e.get(n)),a=s(()=>t,e=>{return n=e,r=t,Object.freeze({$:o(n.$,r.$),tag:o(n.tag,r.tag),name:o(n.name,r.name),value:o(n.value,r.value),validity:o(n.validity,r.validity,(e,t)=>({...e,...t})),touched:n.touched||r.touched,modified:n.modified||r.modified,visited:n.visited||r.visited});var n,r})(r);return e.set(n,a)}function z(e,t){return e.clear(),t?new Map(t.entries()):e}function H(e,n,r){for(let e=0,t=r.length;e<t;e++)n.delete(r[e]);for(const n of e.keys()){r.some(e=>e instanceof RegExp?e.test(n):!!t(e)&&e.trim()===n.trim())&&e.delete(n)}return[n,e]}function x(e,t){const n=new CustomEvent(L.EMIT_FORM_VALUES,{detail:Object.freeze(new Map(t.entries()))});e.dispatchEvent(n)}function B(r){const a=new Map;if(i(r))return void C("[RxFormData] invalid form element for form field storage initialization");const c=r.value,o=new Map;o.set(a,new Map(a.entries()));const u=()=>{const e=o.get(a);return e?new Map(e.entries()):new Map},l=new Set,E=(new Map).set(l,l),T=()=>{const e=E.get(l);return e?new Set(e.values()):new Set};return{storage:u,action:(r,L)=>{switch(r){case _:if(k(L)){const e=s(()=>"",e=>e.trim())(L.name);[...T().keys()].some(r=>t(r)?r.trim()===e.trim():!!n(r)&&r.test(e))&&(o.set(a,$(u(),L)),x(c,u()))}break;case U:o.set(a,z(u())),E.set(l,new Set),x(c,u());break;case d:{const e=Array.from(c.elements).reduce((e,t)=>D(t)?e.concat(t.name):e,[]);E.set(l,new Set(e));break}case m:E.set(l,new Set);break;case R:{const n=Array.isArray(L)?L.filter(e=>t(e)||k(e)):[];n.length&&(o.set(a,function(n,r){return r.reduce((n,r)=>{const a=e(r)?f(r,!0):r.name;return i(a)?n:t(a.value)?(n.delete(a.value.trim()),n):n},n)}(u(),n)),x(c,u()));break}case v:o.set(a,z(u(),a)),x(c,u());break;case I:{const e=Array.isArray(L)?L.filter(e=>t(e)||n(e)):[];e.length&&E.set(l,function(e,t){for(let n=0,r=t.length;n<r;n++)e.add(t[n]);return e}(T(),e));break}case N:if(L&&j(L)){const e=Array.isArray(L.use)?L.use.filter(e=>t(e)||n(e)):[];if(e.length){const t=H(u(),T(),e);E.set(l,t[0]),L.keepvalues||(o.set(a,t[1]),x(c,u()))}}else{const e=Array.isArray(L)?L.filter(e=>t(e)||n(e)):[];if(e.length){const t=H(u(),T(),e);E.set(l,t[0])}}}}}}function X(e,t){t(_,function(e){const t=u(e.target);if(i(t))return F;if(!D(t.value))return F;const n=t.value,r=f(n.name,!0),c=a(`${n.tagName}:${n.type}`.toLowerCase()),s=w(n),o=[T.CHANGE,T.BLUR].includes(e.type),l=[T.CHANGE].includes(e.type),E=[T.FOCUS,T.BLUR].includes(e.type);return Object.freeze({$:a(n),name:r,tag:c,value:s,validity:a(Object.freeze(n.validity)),touched:o,modified:l,visited:E})}(e))}function K(e,t,n,r){return function(a){if(a instanceof CustomEvent)switch(a.type){case L.EMIT_FORM_VALUES:{const e=r.subscribers(),t=null,a=[...n.storage().entries()].reduce((e,[n,r])=>(e[n]=G(r,t),e),{});for(const t of e)t(a);break}}else switch(a.type){case T.SUBMIT:a.preventDefault(),async function(e,t,n){const r=new FormData(e);new Promise((a,c)=>{Promise.resolve().then(()=>{const e=[...t.entries()].reduce((e,[t,n])=>(e[t]=G(n,null),e),{});return Promise.resolve(n(Object.freeze(e),r))}).then(()=>{console.info(`[RxFormData #${e.id}] form submission handler success`),a()}).catch(t=>{console.error(`[RxFormData #${e.id}] form submission handler error(s)`,t),c(t)})})}(e,n.storage(),t);break;case T.FOCUS:case T.INPUT:case T.CHANGE:case T.BLUR:X(a,n.action);break;case T.RESET:n.action(v)}}}return function(e,c){const s=function(e){if(y(e))return a(e);if(i(f(e,!0)))return r;const t=u(document.querySelector("form#"+e.trim()));return i(t)?r:y(t.value)?a(t.value):r}(e);if(i(s))return void C("Invalid form element. Form id provided did not match any form element in the DOM.");const o=B(s)||null,l=o?function(e,t,n){const r=new Set;if(i(e))return void C("[RxFormData] invalid form element for events initialization");const a=new Map;a.set(r,new Set(r.values()));const c=()=>{const e=a.get(r);return e||new Set},s=(e,t)=>{switch(e){case A:t instanceof Function&&a.set(r,new Set(c().values()).add(t));break;case S:if(t instanceof Function){const e=new Set(c().values());e.delete(t),a.set(r,e)}break;case b:a.set(r,new Set)}},o={subscribers:c,action:s},u=e.value,l=K(u,t,n,o);return[...Object.values(T),...Object.values(L)].forEach(e=>{u.addEventListener(e,l,!0)}),{...o,cleanup:()=>{[...Object.values(T),...Object.values(L)].forEach(e=>{u.removeEventListener(e,l,!0)}),s(b),n.action(U)}}}(s,c,o):null;return o&&l?Object.freeze({ACTION_TYPE:Object.freeze(p),register:Object.freeze(e=>(o.action(I,e),Object.freeze(()=>{o.action(N,e)}))),subscribe:Object.freeze(e=>(l.action(A,e),Object.freeze(()=>{l.action(S,e)}))),dispatch:Object.freeze((r,a)=>{switch(r){case p.REGISTER_ALL:o.action(d);break;case p.REGISTER:{const e=Array.isArray(a)?a.reduce((e,r)=>t(r)||n(r)?e.concat(r):e,[]):[];e.length&&o.action(I,e);break}case p.UNREGISTER_ALL:o.action(m),!(!1!==a)&&o.action(v);break;case p.UNREGISTER:{const e=Array.isArray(a)?a.reduce((e,r)=>t(r)||n(r)?e.concat(r):e,[]):[];e.length&&o.action(N,e);break}case p.DESTROY:o.action(v),o.action(m),l.cleanup&&l.cleanup();break;default:return void console.debug(`[RxFormData: #${e}] uknown action dispatched...`,a)}})}):void 0}})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).RxFormData=t()}(this,(function(){"use strict";const e=e=>"string"==typeof e,t=t=>Boolean(e(t)&&t.trim().length),r=e=>"[object RegExp]"===Object.prototype.toString.call(e),n={_is:"None"};function a(e){return{_is:"Some",value:e}}function s(e){return"Some"===e._is}function c(e){return"None"===e._is}function i(e,t){return r=>c(r)?e():t(r.value)}function o(e,t,r){return c(e)&&c(t)?n:s(e)&&s(t)?r?a(r(e.value,t.value)):t:s(e)&&c(t)?e:c(e)&&s(t)?t:n}function u(e){return null===e||void 0===e?n:a(e)}function l(e){return isNaN(Number(e))?n:a(Number(e))}function E(r,s){return e(r)?s?t(r)?a(r):n:a(r):n}const f={INPUT_TEXT:"input:text",INPUT_NUMBER:"input:number",INPUT_EMAIL:"input:email",INPUT_PASSWORD:"input:password",INPUT_CHECKBOX:"input:checkbox",INPUT_RADIO:"input:radio",INPUT_COLOR:"input:color",INPUT_DATE:"input:date",INPUT_DATETIME_LOCAL:"input:datetime-local",INPUT_FILE:"input:file",INPUT_HIDDEN:"input:hidden",INPUT_MONTH:"input:month",INPUT_RANGE:"input:range",INPUT_SEARCH:"input:search",INPUT_TEL:"input:tel",INPUT_TIME:"input:time",INPUT_URL:"input:url",INPUT_WEEK:"input:week",TEXTAREA:"textarea:textarea",SELECT_SINGLE:"select:select-one",SELECT_MULTIPLE:"select:select-multiple"},m={FOCUS:"focus",INPUT:"input",CHANGE:"change",BLUR:"blur",SUBMIT:"submit",RESET:"reset"},d="REGISTER_ALL",T="UNREGISTER_ALL",I="REGISTER",R="UNREGISTER",_="UPSERT_FIELD",A="DELETE_FIELD",v="CLEAR_FIELDS",N="RESET",y="UPSERT_DECODER",O="REMOVE_DECODER",U="CLEAR_DECODERS",S={EMIT_FORM_VALUES:"EMIT_FORM_VALUES"},p="ADD",L="DELETE",b="CLEAR",D={REGISTER:"REGISTER_FIELDS",REGISTER_ALL:"REGISTER_ALL_FIELDS",UNREGISTER:"UNREGISTER_FIELDS",UNREGISTER_ALL:"UNREGISTER_ALL_FIELDS",ADD_DECODERS:"ADD_DECODERS",REMOVE_DECODERS:"REMOVE_DECODERS",CLEAR_DECODERS:"CLEAR_DECODERS",DESTROY:"DESTROY_PROGRAM"};function P(e){return e instanceof HTMLFormElement}function h(e){return e instanceof HTMLInputElement}function g(e){return e instanceof HTMLTextAreaElement}function w(e){return e instanceof HTMLSelectElement}function M(e){return h(e)||w(e)||g(e)}function C(e){return M(e)?h(e)?function(e){if(!h(e))return n;const r=`${e.tagName.toLowerCase()}:${e.type}`;switch(r){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:return a(e.value.trim());case f.INPUT_PASSWORD:return a(e.value);case f.INPUT_NUMBER:case f.INPUT_RANGE:return l(Number(e.value.trim()));case f.INPUT_URL:try{return a(new URL(e.value.trim()).href.trim())}catch(t){return console.warn("[RxFormData] Failed to decode url input field value into URL object",e.value,t),n}case f.INPUT_TEL:return a(e.value.trim().replace(/\D/g,""));case f.INPUT_FILE:return i(()=>n,e=>a(Object.freeze(Array.from(Array(e.length).keys()).reduce((t,r)=>{const n=e.item(r);return n?t.concat(n):t},[]))))(u(e.files));case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:return l(e.valueAsNumber);case f.INPUT_MONTH:try{return a(new Date(e.value+"-1").getTime())}catch(e){return console.error("[RxFormData] Failed to decode month input field value into number",e),n}case f.INPUT_RADIO:case f.INPUT_CHECKBOX:{const s=r.split(":")[1],i=u(e.form);if(c(i))return n;const o=i.value.querySelectorAll(`input[type='${s}'][name='${e.name}']:checked`);return a(Object.freeze(Array.from(o).map((r,n)=>h(r)&&t(r.value)?r.value.trim():`${e.name}[${n}]`)))}default:return n}}(e):w(e)?function(e){if(!w(e))return n;switch(`${e.tagName.toLowerCase()}:${e.type}`){case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return a(Object.freeze(Array.from(e.selectedOptions).map((r,n)=>t(r.value)?r.value.trim():`${e.name}[${n}]`)));default:return n}}(e):g(e)?function(e){return g(e)?a(e.value.trim()):n}(e):n:n}function j(t){return!!e(t)||("number"==typeof t||!(!Array.isArray(t)||!t.every(e)&&!t.every(e=>e instanceof File)))}function F(e){return t(e)&&Object.keys(f).includes(e)}function k(n){return e(n)?t(n.trim()):r(n)}function z(e){if(e instanceof Error)throw e;const t=new Error("[RxFormData] ERROR!");throw t.details=JSON.stringify(e),t}function G(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&"Object"===e.constructor.name}const $=Object.freeze({$:n,tag:n,name:n,value:n,validity:a(Object.freeze({badInput:!1,customError:!1,patternMismatch:!1,rangeOverflow:!1,rangeUnderflow:!1,stepMismatch:!1,tooLong:!1,tooShort:!1,typeMismatch:!1,valid:!1,valueMissing:!1})),touched:!1,modified:!1,visited:!1});function x(e){if(!G(e))return!1;const r=Object.keys($);if(!Object.keys(e).every(e=>r.includes(e)))return!1;const n=(e,r)=>G(e)&&t(e._is)&&["none","some"].includes(e._is)&&("some"!==e._is||r(e.value));return Object.entries(e).reduce((e,[r,a])=>{switch(r){case"$":return e&&n(a,M);case"tag":return e&&n(a,F);case"name":return e&&n(a,t);case"value":return e&&n(a,j);case"validity":return e&&n(a,e=>G(e)||e instanceof ValidityState);case"touched":case"visited":case"modified":return"boolean"==typeof a;default:return!1}},!0)}function H(e,t){const r=i(()=>t,e=>e)(e.$),n=i(()=>t,e=>e)(e.tag),a=i(()=>t,e=>e)(e.name),s=i(()=>t,e=>e)(e.validity);return Object.freeze({$:r,tag:n,name:a,value:(()=>{if(n===t)return t;const r=i(()=>t,e=>e)(e.value);if(r===t)return r;switch(n){case f.INPUT_TEXT:case f.INPUT_SEARCH:case f.INPUT_EMAIL:case f.INPUT_COLOR:case f.INPUT_HIDDEN:case f.TEXTAREA:case f.INPUT_URL:case f.INPUT_TEL:case f.INPUT_PASSWORD:return String(r);case f.INPUT_NUMBER:case f.INPUT_RANGE:case f.INPUT_DATE:case f.INPUT_DATETIME_LOCAL:case f.INPUT_TIME:case f.INPUT_WEEK:case f.INPUT_MONTH:return Number(r);case f.INPUT_FILE:return Array.isArray(r)?Object.freeze(r.map(e=>Object.freeze(e))):[];case f.INPUT_RADIO:case f.INPUT_CHECKBOX:case f.SELECT_SINGLE:case f.SELECT_MULTIPLE:return Array.isArray(r)?Object.freeze(r.map(String)):[];default:return t}})(),validity:s,touched:e.touched,modified:e.modified,visited:e.visited})}function B(e){if(!G(e))return n;if(!t(e.name))return n;if(!Array.isArray(e.use))return n;if(!e.use.every(e=>e instanceof Function))return n;if(!(Array.isArray(e.messages)&&e.messages.every(t)||e.messages instanceof Function))return n;return a({name:e.name.trim(),input:[],use:e.use,messages:Array.isArray(e.messages)?()=>e.messages:e.messages})}function V(e){return s(B(e))}async function X(e,r){return new Promise(n=>{Promise.resolve().then(()=>Promise.all(e.use.map(e=>e(r)))).then(t=>t.every(e=>!0===e)?Promise.resolve([]):Promise.resolve(e.messages({inputs:r,outputs:t}))).then(r=>{Array.isArray(r)?r.length?n({decoder:e.name,success:!1,errors:r.filter(t)}):n({decoder:e.name,success:!0,errors:[]}):t(r)?n({decoder:e.name,success:!1,errors:[r]}):n({decoder:e.name,success:!1,errors:["Decoder error(s): "+JSON.stringify(r)]})}).catch(t=>{console.error("[RxFormData] An error occured while running decoder resolvers",e,t),n({decoder:e.name,success:!1,errors:["Decoder implementation error(s)"]})})})}function K(e,t){if(c(t.name))return e;const r=t.name.value,n=u(e.get(r)),a=i(()=>t,e=>{return r=e,n=t,Object.freeze({$:o(r.$,n.$),tag:o(r.tag,n.tag),name:o(r.name,n.name),value:o(r.value,n.value),validity:o(r.validity,n.validity),touched:r.touched||n.touched,modified:r.modified||n.modified,visited:r.visited||n.visited});var r,n})(n);return e.set(r,a)}function W(e,t){return e.clear(),t?new Map(t.entries()):e}function Y(e,r,n){for(let e=0,t=n.length;e<t;e++)r.delete(n[e]);for(const r of e.keys()){n.some(e=>e instanceof RegExp?e.test(r):!!t(e)&&e.trim()===r.trim())&&e.delete(r)}return[r,e]}function q(e,t){const r=new CustomEvent(S.EMIT_FORM_VALUES,{detail:Object.freeze(new Map(t.entries()))});e.dispatchEvent(r)}function J(n){const a=new Map;if(c(n))return void z("[RxFormData] invalid form element for form field storage initialization");const s=n.value,o=new Map;o.set(a,new Map(a.entries()));const u=()=>{const e=o.get(a);return e?new Map(e.entries()):new Map},l=new Set,f=(new Map).set(l,l),m=()=>{const e=f.get(l);return e?new Set(e.values()):new Set},S=new Map,p=(new Map).set(S,S),L=()=>{const e=p.get(S);return e?new Map(e.entries()):new Map};return{storage:u,decoders:L,action:(n,b)=>{switch(n){case _:if(x(b)){const e=i(()=>"",e=>e.trim())(b.name);[...m().keys()].some(n=>t(n)?n.trim()===e.trim():!!r(n)&&n.test(e))&&(o.set(a,K(u(),b)),q(s,u()))}break;case v:o.set(a,W(u())),f.set(l,new Set),p.set(S,new Map),q(s,u());break;case d:{const e=Array.from(s.elements).reduce((e,t)=>M(t)?e.concat(t.name):e,[]);f.set(l,new Set(e));break}case T:f.set(l,new Set);break;case A:{const r=Array.isArray(b)?b.filter(e=>t(e)||x(e)):[];r.length&&(o.set(a,function(r,n){return n.reduce((r,n)=>{const a=e(n)?E(n,!0):n.name;return c(a)?r:t(a.value)?(r.delete(a.value.trim()),r):r},r)}(u(),r)),q(s,u()));break}case N:o.set(a,W(u(),a)),q(s,u());break;case I:{const e=Array.isArray(b)?b.filter(e=>t(e)||r(e)):[];e.length&&f.set(l,function(e,t){for(let r=0,n=t.length;r<n;r++)e.add(t[r]);return e}(m(),e));break}case R:if(b&&G(b)){const e=Array.isArray(b.use)?b.use.filter(e=>t(e)||r(e)):[];if(e.length){const t=Y(u(),m(),e);f.set(l,t[0]),b.keepvalues||(o.set(a,t[1]),q(s,u()))}}else{const e=Array.isArray(b)?b.filter(e=>t(e)||r(e)):[];if(e.length){const t=Y(u(),m(),e);f.set(l,t[0])}}break;case y:if(Array.isArray(b)&&b.every(V)){const e=L();for(let t=0,r=b.length;t<r;t++){const r=b[t];e.set(r.name,r)}p.set(S,e)}break;case O:if(Array.isArray(b)){const e=L();for(let n=0,a=b.length;n<a;n++){const a=b[n];if(k(a))for(const[n]of e)(t(a)&&a===n||r(a)&&a.test(n))&&e.delete(n)}p.set(S,e)}break;case U:p.set(S,new Map)}}}}function Q(e,t){t(_,function(e){const t=u(e.target);if(c(t))return $;if(!M(t.value))return $;const r=t.value,n=E(r.name,!0),s=a(`${r.tagName}:${r.type}`.toLowerCase()),i=C(r),o=[m.CHANGE,m.BLUR].includes(e.type),l=[m.CHANGE].includes(e.type),f=[m.FOCUS,m.BLUR].includes(e.type);return Object.freeze({$:a(r),name:n,tag:s,value:i,validity:a(Object.freeze(r.validity)),touched:o,modified:l,visited:f})}(e))}function Z(e,t,r,n){return function(a){if(a instanceof CustomEvent)switch(a.type){case S.EMIT_FORM_VALUES:{const e=n.subscribers(),t=null,a=Object.freeze([...r.storage().entries()].reduce((e,[r,n])=>(e[r]=H(n,t),e),{}));Promise.all([...r.decoders().values()].map(e=>X(e,a))).then(t=>{const r=t.reduce((e,t)=>(e[t.decoder]=Object.freeze(t),e),{});for(const t of e)t(a,Object.freeze(r))}).catch(t=>{const r=new Error("[RxFormData] An an error occured while running decoders. Check the error details for more info.");r.details=t;for(const t of e)t(a,r)});break}}else switch(a.type){case m.SUBMIT:a.preventDefault(),async function(e,t,r,n){const a=new FormData(e);new Promise((s,c)=>{Promise.resolve().then(()=>{const e=[...t.entries()].reduce((e,[t,r])=>(e[t]=H(r,null),e),{});return Promise.all([null,e,Promise.all(Array.from(r.values()).map(t=>X(t,e)))])}).then(([e,t,r])=>{const s=r.reduce((e,t)=>Object.assign({},e,Object.freeze(t)),{});return Promise.resolve(n(Object.freeze(t),Object.freeze(s),a))}).then(()=>{console.info(`[RxFormData #${e.id}] form submission handler success`),s()}).catch(t=>{console.error(`[RxFormData #${e.id}] form submission handler error(s)`,t),c(t)})})}(e,r.storage(),r.decoders(),t);break;case m.FOCUS:case m.INPUT:case m.CHANGE:case m.BLUR:Q(a,r.action);break;case m.RESET:r.action(N)}}}return function(e,i){const o=function(e){if(P(e))return a(e);if(c(E(e,!0)))return n;const t=u(document.querySelector("form#"+e.trim()));return c(t)?n:P(t.value)?a(t.value):n}(e);if(c(o))return void z("Invalid form element. Form id provided did not match any form element in the DOM.");const l=J(o)||null,f=l?function(e,t,r){const n=new Set;if(c(e))return void z("[RxFormData] invalid form element for events initialization");const a=new Map;a.set(n,new Set(n.values()));const s=()=>{const e=a.get(n);return e||new Set},i=(e,t)=>{switch(e){case p:t instanceof Function&&a.set(n,new Set(s().values()).add(t));break;case L:if(t instanceof Function){const e=new Set(s().values());e.delete(t),a.set(n,e)}break;case b:a.set(n,new Set)}},o={subscribers:s,action:i},u=e.value,l=Z(u,t,r,o);return[...Object.values(m),...Object.values(S)].forEach(e=>{u.addEventListener(e,l,!0)}),{...o,cleanup:()=>{[...Object.values(m),...Object.values(S)].forEach(e=>{u.removeEventListener(e,l,!0)}),i(b),r.action(v)}}}(o,i,l):null;return l&&f?Object.freeze({ACTION_TYPE:Object.freeze(D),register:Object.freeze(e=>(l.action(I,e),Object.freeze(()=>{l.action(R,e)}))),subscribe:Object.freeze(e=>(f.action(p,e),Object.freeze(()=>{f.action(L,e)}))),dispatch:Object.freeze((n,a)=>{switch(n){case D.REGISTER_ALL:l.action(d);break;case D.REGISTER:{const e=Array.isArray(a)?a.reduce((e,n)=>t(n)||r(n)?e.concat(n):e,[]):[];e.length&&l.action(I,e);break}case D.UNREGISTER_ALL:l.action(T),!(!1!==a)&&l.action(N);break;case D.UNREGISTER:{const e=Array.isArray(a)?a.reduce((e,n)=>t(n)||r(n)?e.concat(n):e,[]):[];e.length&&l.action(R,e);break}case D.DESTROY:l.action(N),l.action(T),l.action(U),f.cleanup&&f.cleanup();break;case D.ADD_DECODERS:if(Array.isArray(a)){const e=a.reduce((e,t)=>{const r=B(t);return s(r)?e.concat(r.value):e},[]);e.length&&l.action(y,e)}break;case D.REMOVE_DECODERS:Array.isArray(a)&&l.action(O,a.filter(k));break;case D.CLEAR_DECODERS:l.action(U);break;default:return void console.debug(`[RxFormData: #${e}] uknown action dispatched...`,a)}})}):void 0}})); |
@@ -41,2 +41,5 @@ export declare const HTML_FORM_FIELD_TAG: { | ||
readonly RESET: "RESET"; | ||
readonly UPSERT_DECODER: "UPSERT_DECODER"; | ||
readonly REMOVE_DECODER: "REMOVE_DECODER"; | ||
readonly CLEAR_DECODERS: "CLEAR_DECODERS"; | ||
}; | ||
@@ -56,3 +59,6 @@ export declare const HTML_FORM_CUSTOM_EVENT_TYPE: { | ||
readonly UNREGISTER_ALL: "UNREGISTER_ALL_FIELDS"; | ||
readonly ADD_DECODERS: "ADD_DECODERS"; | ||
readonly REMOVE_DECODERS: "REMOVE_DECODERS"; | ||
readonly CLEAR_DECODERS: "CLEAR_DECODERS"; | ||
readonly DESTROY: "DESTROY_PROGRAM"; | ||
}; |
import { HTML_FORM_FIELD_TAG, HTML_FORM_NATIVE_EVENT_TYPE, FORM_FIELD_STORAGE_ACTION_TYPE, HTML_FORM_CUSTOM_EVENT_TYPE, FORM_FIELDS_SUBSCRIBERS_ACTION_TYPE, PROGRAM_INTERFACE_ACTION_TYPE } from "../constants"; | ||
import { FormField, SerializedFormField } from "./Field"; | ||
import { FormFieldStorage, FormFieldSelectorExpression } from "../repository"; | ||
import { FormFieldStorage, FormDecoders } from "../repository"; | ||
import { DecoderResult, Decoder } from "./Decoder"; | ||
export declare type Predicate<T> = (x: T) => boolean; | ||
export declare type SubmissionHandlerConfigOption = <T, U = never>(formvalues: Readonly<Record<string, SerializedFormField<U>>>, formdata: FormData) => T; | ||
export declare type FormFieldStorageActionFn = (type: FormFieldStorageActionType, payload?: FormField | Array<string | FormField> | FormFieldSelectorExpression[]) => void; | ||
export declare type SubmissionHandlerConfigOption = <T, U = never>(formvalues: Readonly<Record<string, SerializedFormField<U>>>, formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>>, formdata: FormData) => T; | ||
export declare type FormFieldStorageActionFn = (type: FormFieldStorageActionType, payload?: FormFieldSelectorExpression | FormField | Array<string | FormField> | FormFieldSelectorExpression[] | { | ||
use: FormFieldSelectorExpression[]; | ||
keepvalues: boolean; | ||
} | Decoder[]) => void; | ||
export declare type FormFieldStorageInterface = Readonly<{ | ||
storage: () => FormFieldStorage; | ||
decoders: () => FormDecoders; | ||
action: FormFieldStorageActionFn; | ||
@@ -18,5 +23,6 @@ cleanup?: () => void; | ||
}>; | ||
export declare type FormFieldSubscriber = <T>(formvalues: Readonly<Record<string, SerializedFormField<T>>>) => void; | ||
export declare type FormFieldSubscriber = <T>(formvalues: Readonly<Record<string, SerializedFormField<T>>>, formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>>) => void; | ||
export declare type HTMLFormFieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; | ||
export declare type HTMLFormFieldValue = string | number | ReadonlyArray<string> | ReadonlyArray<File>; | ||
export declare type FormFieldSelectorExpression = string | RegExp; | ||
export declare type HTMLFormFieldTag = typeof HTML_FORM_FIELD_TAG[keyof typeof HTML_FORM_FIELD_TAG]; | ||
@@ -23,0 +29,0 @@ export declare type HTMLFormNativeEventType = typeof HTML_FORM_NATIVE_EVENT_TYPE[keyof typeof HTML_FORM_NATIVE_EVENT_TYPE]; |
@@ -1,8 +0,9 @@ | ||
import { FormFieldStorage } from "./repository"; | ||
import { FormFieldStorage, FormDecoders } from "./repository"; | ||
import { FormField, SerializedFormField } from "./datatypes/Field"; | ||
import { FormFieldStorageActionFn, FormFieldStorageInterface, FormEventsInterface, SubmissionHandlerConfigOption } from "./datatypes/base"; | ||
import { Option } from "./datatypes/Option"; | ||
export declare function onsubmit<T>($form: HTMLFormElement, storage: FormFieldStorage, handler: <K extends T, U>(formvalues: Readonly<Record<string, SerializedFormField<U>>>, formdata: FormData) => K): Promise<T>; | ||
import { DecoderResult } from "./datatypes/Decoder"; | ||
export declare function onsubmit<T>($form: HTMLFormElement, storage: FormFieldStorage, decoders: FormDecoders, handler: <K extends T, U>(formvalues: Readonly<Record<string, SerializedFormField<U>>>, formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>>, formdata: FormData) => K): Promise<T>; | ||
export declare function onfieldevent(evt: Event, action: FormFieldStorageActionFn): void; | ||
export declare function getFormEventListener($target: HTMLFormElement, submissionHanlder: SubmissionHandlerConfigOption, storageinterface: FormFieldStorageInterface, subscribersinterface: FormEventsInterface): (evt: Event | CustomEvent<Readonly<Map<string, FormField>>>) => void; | ||
export declare function initialize($formElement: Option<HTMLFormElement>, submissionHanlder: SubmissionHandlerConfigOption, storageinterface: FormFieldStorageInterface): FormEventsInterface | void; |
import { Option } from "../datatypes/Option"; | ||
import { HTMLFormFieldElement, HTMLFormFieldValue, HTMLFormFieldTag } from "../datatypes/base"; | ||
import { HTMLFormFieldElement, HTMLFormFieldValue, HTMLFormFieldTag, FormFieldSelectorExpression } from "../datatypes/base"; | ||
export declare function isFormElement(x: unknown): x is HTMLFormElement; | ||
@@ -17,1 +17,2 @@ export declare function isInputFieldElement(x: unknown): x is HTMLInputElement; | ||
export declare function isFormFieldInternalTag(x: unknown): x is HTMLFormFieldTag; | ||
export declare function isFormFieldSelectorExpression(x: unknown): x is FormFieldSelectorExpression; |
import { FormField } from "./datatypes/Field"; | ||
import { Option } from "./datatypes/Option"; | ||
import { FormFieldStorageInterface } from "./datatypes/base"; | ||
import { FormFieldStorageInterface, FormFieldSelectorExpression } from "./datatypes/base"; | ||
import { Decoder } from "./datatypes/Decoder"; | ||
export declare type FormFieldStorage = Map<string, FormField>; | ||
export declare type FormFieldSelectorExpression = string | RegExp; | ||
export declare type FormFieldRegister = Set<FormFieldSelectorExpression>; | ||
export declare type FormDecoders = Map<string, Decoder>; | ||
export declare function put(storage: FormFieldStorage, msg: FormField): FormFieldStorage; | ||
@@ -8,0 +9,0 @@ export declare function remove(storage: FormFieldStorage, selection: Array<string | FormField>): FormFieldStorage; |
{ | ||
"name": "@metronlabs/rx-form-data", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "Framework agnostic reactive form data streaming", | ||
@@ -35,6 +35,7 @@ "keywords": [ | ||
"lint": "eslint --ext .js,.ts src/* --fix && prettier --write \"src/**/*.{js,ts}\"", | ||
"clean": "rimraf lib/*", | ||
"clean": "rimraf lib/* && rimraf examples/dist/*", | ||
"prebuild": "npm run lint && npm run clean", | ||
"build": "rollup -c rollup.config.ts && ./node_modules/.bin/ttsc -p ./tsconfig.types.json", | ||
"prepare": "npm run build" | ||
"prepare": "npm run build", | ||
"postbuild": "cp lib/index.umd.js examples/dist" | ||
}, | ||
@@ -41,0 +42,0 @@ "devDependencies": { |
@@ -42,3 +42,6 @@ export const HTML_FORM_FIELD_TAG = { | ||
CLEAR: "CLEAR_FIELDS", | ||
RESET: "RESET" | ||
RESET: "RESET", | ||
UPSERT_DECODER: "UPSERT_DECODER", | ||
REMOVE_DECODER: "REMOVE_DECODER", | ||
CLEAR_DECODERS: "CLEAR_DECODERS" | ||
} as const; | ||
@@ -61,3 +64,6 @@ | ||
UNREGISTER_ALL: "UNREGISTER_ALL_FIELDS", | ||
ADD_DECODERS: "ADD_DECODERS", | ||
REMOVE_DECODERS: "REMOVE_DECODERS", | ||
CLEAR_DECODERS: "CLEAR_DECODERS", | ||
DESTROY: "DESTROY_PROGRAM" | ||
} as const; |
@@ -10,3 +10,4 @@ import { | ||
import { FormField, SerializedFormField } from "@datatypes/Field"; | ||
import { FormFieldStorage, FormFieldSelectorExpression } from "@/repository"; | ||
import { FormFieldStorage, FormDecoders } from "@/repository"; | ||
import { DecoderResult, Decoder } from "@datatypes/Decoder"; | ||
@@ -16,2 +17,3 @@ export type Predicate<T> = (x: T) => boolean; | ||
formvalues: Readonly<Record<string, SerializedFormField<U>>>, | ||
formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>>, | ||
formdata: FormData | ||
@@ -22,5 +24,8 @@ ) => T; | ||
payload?: | ||
| FormFieldSelectorExpression | ||
| FormField | ||
| Array<string | FormField> | ||
| FormFieldSelectorExpression[] | ||
| { use: FormFieldSelectorExpression[]; keepvalues: boolean } | ||
| Decoder[] | ||
) => void; | ||
@@ -30,2 +35,3 @@ | ||
storage: () => FormFieldStorage; | ||
decoders: () => FormDecoders; | ||
action: FormFieldStorageActionFn; | ||
@@ -47,3 +53,4 @@ cleanup?: () => void; | ||
export type FormFieldSubscriber = <T>( | ||
formvalues: Readonly<Record<string, SerializedFormField<T>>> | ||
formvalues: Readonly<Record<string, SerializedFormField<T>>>, | ||
formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>> | ||
) => void; | ||
@@ -62,2 +69,4 @@ | ||
export type FormFieldSelectorExpression = string | RegExp; | ||
export type HTMLFormFieldTag = typeof HTML_FORM_FIELD_TAG[keyof typeof HTML_FORM_FIELD_TAG]; | ||
@@ -64,0 +73,0 @@ export type HTMLFormNativeEventType = typeof HTML_FORM_NATIVE_EVENT_TYPE[keyof typeof HTML_FORM_NATIVE_EVENT_TYPE]; |
@@ -58,3 +58,17 @@ import { | ||
value: none as Option<HTMLFormFieldValue>, | ||
validity: none as Option<Readonly<ValidityState>>, | ||
validity: some( | ||
Object.freeze({ | ||
badInput: false, | ||
customError: false, | ||
patternMismatch: false, | ||
rangeOverflow: false, | ||
rangeUnderflow: false, | ||
stepMismatch: false, | ||
tooLong: false, | ||
tooShort: false, | ||
typeMismatch: false, | ||
valid: false, | ||
valueMissing: false | ||
}) | ||
), | ||
touched: false, | ||
@@ -117,3 +131,4 @@ modified: false, | ||
value, | ||
(u: unknown) => u instanceof ValidityState | ||
//TODO: make a proper predicate for the validity datatype | ||
(u: unknown) => isPlainObject(u) || u instanceof ValidityState | ||
) | ||
@@ -139,7 +154,2 @@ ); | ||
export function concat(x: FormField, y: FormField): FormField { | ||
const concatValidity = ( | ||
a: Readonly<ValidityState>, | ||
b: Readonly<ValidityState> | ||
): Readonly<ValidityState> => ({ ...a, ...b }); | ||
return Object.freeze({ | ||
@@ -150,3 +160,3 @@ $: optionconcat(x.$, y.$), | ||
value: optionconcat(x.value, y.value), | ||
validity: optionconcat(x.validity, y.validity, concatValidity), | ||
validity: optionconcat(x.validity, y.validity), | ||
touched: x.touched || y.touched, | ||
@@ -153,0 +163,0 @@ modified: x.modified || y.modified, |
@@ -1,2 +0,2 @@ | ||
import { FormFieldStorage } from "@/repository"; | ||
import { FormFieldStorage, FormDecoders } from "@/repository"; | ||
import { | ||
@@ -26,7 +26,11 @@ FormField, | ||
import { run as runDecoder, DecoderResult } from "@datatypes/Decoder"; | ||
export async function onsubmit<T>( | ||
$form: HTMLFormElement, | ||
storage: FormFieldStorage, | ||
decoders: FormDecoders, | ||
handler: <K extends T, U>( | ||
formvalues: Readonly<Record<string, SerializedFormField<U>>>, | ||
formvalidation: Error | Readonly<Record<string, Readonly<DecoderResult>>>, | ||
formdata: FormData | ||
@@ -51,4 +55,27 @@ ) => K | ||
); | ||
return Promise.all([ | ||
nilvalue, | ||
formvalues, | ||
Promise.all( | ||
Array.from(decoders.values()).map((decoder) => | ||
runDecoder(decoder, formvalues) | ||
) | ||
) | ||
]); | ||
}) | ||
.then(([nil, formvalues, decoderResults]) => { | ||
const validation = decoderResults.reduce( | ||
(collection: Record<string, Readonly<DecoderResult>>, result) => { | ||
return Object.assign({}, collection, Object.freeze(result)); | ||
}, | ||
{} as Record<string, Readonly<DecoderResult>> | ||
); | ||
return Promise.resolve( | ||
handler<T, typeof nilvalue>(Object.freeze(formvalues), formdata) | ||
handler<T, typeof nil>( | ||
Object.freeze(formvalues), | ||
Object.freeze(validation), | ||
formdata | ||
) | ||
); | ||
@@ -93,16 +120,48 @@ }) | ||
const nilvalue = null; | ||
const formvalues = [...storageinterface.storage().entries()].reduce( | ||
( | ||
values: Record<string, SerializedFormField<typeof nilvalue>>, | ||
[fieldname, fielddata] | ||
) => { | ||
values[fieldname] = serialize(fielddata, nilvalue); | ||
return values; | ||
}, | ||
{} as Record<string, SerializedFormField<typeof nilvalue>> | ||
const formvalues = Object.freeze( | ||
[...storageinterface.storage().entries()].reduce( | ||
( | ||
values: Record<string, SerializedFormField<typeof nilvalue>>, | ||
[fieldname, fielddata] | ||
) => { | ||
values[fieldname] = serialize(fielddata, nilvalue); | ||
return values; | ||
}, | ||
{} as Record<string, SerializedFormField<typeof nilvalue>> | ||
) | ||
); | ||
for (const fn of subscribers) { | ||
fn(formvalues); | ||
} | ||
Promise.all( | ||
[...storageinterface.decoders().values()].map((decoder) => | ||
runDecoder(decoder, formvalues) | ||
) | ||
) | ||
.then((decoderResults) => { | ||
const validation = decoderResults.reduce( | ||
( | ||
collection: Record<string, Readonly<DecoderResult>>, | ||
result | ||
) => { | ||
collection[result.decoder] = Object.freeze(result); | ||
return collection; | ||
}, | ||
{} as Record<string, Readonly<DecoderResult>> | ||
); | ||
for (const fn of subscribers) { | ||
fn(formvalues, Object.freeze(validation)); | ||
} | ||
}) | ||
.catch((err) => { | ||
const error = new Error( | ||
"[RxFormData] An an error occured while running decoders. Check the error details for more info." | ||
); | ||
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore | ||
//@ts-ignore | ||
error.details = err; | ||
for (const fn of subscribers) { | ||
fn(formvalues, error); | ||
} | ||
}); | ||
break; | ||
@@ -118,2 +177,3 @@ } | ||
storageinterface.storage(), | ||
storageinterface.decoders(), | ||
submissionHanlder | ||
@@ -120,0 +180,0 @@ ); |
@@ -1,8 +0,5 @@ | ||
import { $getform } from "@operators/dom"; | ||
import { isNone } from "@datatypes/Option"; | ||
import { $getform, isFormFieldSelectorExpression } from "@operators/dom"; | ||
import { isNone, isSome } from "@datatypes/Option"; | ||
import { panic } from "@operators/error"; | ||
import { | ||
initialize as repositoryInitialization, | ||
FormFieldSelectorExpression | ||
} from "@/repository"; | ||
import { initialize as repositoryInitialization } from "@/repository"; | ||
import { initialize as eventsInitialization } from "@/events"; | ||
@@ -13,3 +10,4 @@ import { | ||
ProgramInterfaceActionType, | ||
FormFieldSubscriber | ||
FormFieldSubscriber, | ||
FormFieldSelectorExpression | ||
} from "@datatypes/base"; | ||
@@ -22,2 +20,3 @@ import { | ||
import { isNonEmptyString, isRegExp } from "@operators/string"; | ||
import { create as createDecoder, Decoder } from "@datatypes/Decoder"; | ||
@@ -130,2 +129,3 @@ export default function RxFormData( | ||
repository.action(FORM_FIELD_STORAGE_ACTION_TYPE.UNREGISTER_ALL); | ||
repository.action(FORM_FIELD_STORAGE_ACTION_TYPE.CLEAR_DECODERS); | ||
if (events.cleanup) { | ||
@@ -136,2 +136,37 @@ events.cleanup(); | ||
} | ||
case PROGRAM_INTERFACE_ACTION_TYPE.ADD_DECODERS: { | ||
if (Array.isArray(payload)) { | ||
const params = payload.reduce( | ||
(decoders: Decoder[], config: unknown) => { | ||
const decoder = createDecoder(config); | ||
if (isSome(decoder)) return decoders.concat(decoder.value); | ||
return decoders; | ||
}, | ||
[] as Decoder[] | ||
); | ||
if (params.length) | ||
repository.action( | ||
FORM_FIELD_STORAGE_ACTION_TYPE.UPSERT_DECODER, | ||
params | ||
); | ||
} | ||
break; | ||
} | ||
case PROGRAM_INTERFACE_ACTION_TYPE.REMOVE_DECODERS: { | ||
if (Array.isArray(payload)) { | ||
repository.action( | ||
FORM_FIELD_STORAGE_ACTION_TYPE.REMOVE_DECODER, | ||
payload.filter(isFormFieldSelectorExpression) | ||
); | ||
} | ||
break; | ||
} | ||
case PROGRAM_INTERFACE_ACTION_TYPE.CLEAR_DECODERS: { | ||
repository.action(FORM_FIELD_STORAGE_ACTION_TYPE.CLEAR_DECODERS); | ||
break; | ||
} | ||
default: { | ||
@@ -138,0 +173,0 @@ console.debug( |
@@ -14,5 +14,6 @@ import { | ||
HTMLFormFieldValue, | ||
HTMLFormFieldTag | ||
HTMLFormFieldTag, | ||
FormFieldSelectorExpression | ||
} from "@datatypes/base"; | ||
import { isNonEmptyString, isString } from "@operators/string"; | ||
import { isNonEmptyString, isString, isRegExp } from "@operators/string"; | ||
import { HTML_FORM_FIELD_TAG } from "@/constants"; | ||
@@ -256,1 +257,10 @@ | ||
} | ||
export function isFormFieldSelectorExpression( | ||
x: unknown | ||
): x is FormFieldSelectorExpression { | ||
if (isString(x)) { | ||
return isNonEmptyString(x.trim()); | ||
} | ||
return isRegExp(x); | ||
} |
@@ -18,3 +18,4 @@ import { | ||
FormFieldStorageActionType, | ||
FormFieldStorageInterface | ||
FormFieldStorageInterface, | ||
FormFieldSelectorExpression | ||
} from "@datatypes/base"; | ||
@@ -28,7 +29,11 @@ import { | ||
import { isPlainObject } from "@operators/struct"; | ||
import { isFormFieldElement } from "./operators/dom"; | ||
import { | ||
isFormFieldElement, | ||
isFormFieldSelectorExpression | ||
} from "./operators/dom"; | ||
import { Decoder, isDecoder } from "@datatypes/Decoder"; | ||
export type FormFieldStorage = Map<string, FormField>; | ||
export type FormFieldSelectorExpression = string | RegExp; | ||
export type FormFieldRegister = Set<FormFieldSelectorExpression>; | ||
export type FormDecoders = Map<string, Decoder>; | ||
@@ -162,2 +167,15 @@ export function put( | ||
const decoders = new Map<string, Decoder>(); | ||
const decodersref = new Map<FormDecoders, FormDecoders>().set( | ||
decoders, | ||
decoders | ||
); | ||
const getdecoders = (): FormDecoders => { | ||
const latest = decodersref.get(decoders); | ||
return latest | ||
? new Map<string, Decoder>(latest.entries()) | ||
: new Map<string, Decoder>(); | ||
}; | ||
const action = ( | ||
@@ -171,2 +189,3 @@ type: FormFieldStorageActionType, | ||
| { use: FormFieldSelectorExpression[]; keepvalues: boolean } | ||
| Decoder[] | ||
): void => { | ||
@@ -198,2 +217,3 @@ switch (type) { | ||
registerref.set(register, new Set<FormFieldSelectorExpression>()); | ||
decodersref.set(decoders, new Map<string, Decoder>()); | ||
publish($target, getstorage()); | ||
@@ -284,2 +304,38 @@ break; | ||
} | ||
case FORM_FIELD_STORAGE_ACTION_TYPE.UPSERT_DECODER: { | ||
if (Array.isArray(payload) && payload.every(isDecoder)) { | ||
const collection = getdecoders(); | ||
for (let idx = 0, length = payload.length; idx < length; idx++) { | ||
const decoder = payload[idx] as Decoder; | ||
collection.set(decoder.name, decoder); | ||
} | ||
decodersref.set(decoders, collection); | ||
} | ||
break; | ||
} | ||
case FORM_FIELD_STORAGE_ACTION_TYPE.REMOVE_DECODER: { | ||
if (Array.isArray(payload)) { | ||
const collection = getdecoders(); | ||
for (let idx = 0, length = payload.length; idx < length; idx++) { | ||
const expression = payload[idx]; | ||
if (!isFormFieldSelectorExpression(expression)) continue; | ||
for (const [key] of collection) { | ||
if (isNonEmptyString(expression) && expression === key) { | ||
collection.delete(key); | ||
} else if (isRegExp(expression) && expression.test(key)) { | ||
collection.delete(key); | ||
} | ||
} | ||
} | ||
decodersref.set(decoders, collection); | ||
} | ||
break; | ||
} | ||
case FORM_FIELD_STORAGE_ACTION_TYPE.CLEAR_DECODERS: { | ||
decodersref.set(decoders, new Map<string, Decoder>()); | ||
break; | ||
} | ||
} | ||
@@ -290,4 +346,5 @@ }; | ||
storage: getstorage, | ||
decoders: getdecoders, | ||
action | ||
} as const; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
101444
31
1989