-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathajaxial.min.js
2 lines (2 loc) · 5.04 KB
/
ajaxial.min.js
1
2
// Ajaxial v1.0.0 | https://github.com/kgscialdone/ajaxial
const Ajaxial=new function Ajaxial(){(fn=>document.readyState!=="loading"?fn():document.addEventListener("DOMContentLoaded",fn))((()=>this.process(document.body)));const defaultKey=Symbol("Ajaxial.default");const orDefault=(obj,key)=>obj[key??obj[defaultKey]];Object.freeze(Object.assign(this,{version:"1.0.0",default:defaultKey,methods:{[defaultKey]:"get",get:request.bind(this,"GET",true),delete:request.bind(this,"DELETE",true),post:request.bind(this,"POST",false),put:request.bind(this,"PUT",false),patch:request.bind(this,"PATCH",false)},swapStrategies:{[defaultKey]:"innerhtml",innerhtml:(target,fragment)=>target.replaceChildren(fragment),outerhtml:(target,fragment)=>target.replaceWith(fragment),beforebegin:(target,fragment)=>target.replaceWith(fragment,target),afterbegin:(target,fragment)=>target.prepend(fragment),beforeend:(target,fragment)=>target.append(fragment),afterend:(target,fragment)=>target.replaceWith(target,fragment),none:null},requestEncodings:{[defaultKey]:"application/x-www-form-urlencoded","application/x-www-form-urlencoded":params=>new URLSearchParams(params),"application/json":JSON.stringify,"multipart/form-data":params=>Object.entries(params).reduce(((a,[k,v])=>(a.append(k,v),a)),new FormData)},responseConverters:{[defaultKey]:"html",html:body=>parent=>{let range=document.createRange();range.setStart(parent,0);return range.createContextualFragment(body)},plaintext(body){let fragment=document.createDocumentFragment();fragment.append(document.createTextNode(body));return fragment}},defaultEvents:{form:"submit",input:"change",select:"change",textarea:"change"},process(rootNode){const nodes=[...rootNode.querySelectorAll("[ajxl-path]"),rootNode.matches?.("[ajxl-path]")?rootNode:null];for(let node of nodes.filter((n=>n&&!n.ajxl))){let nodeRef=new WeakRef(node);node.ajxl=new Proxy({},{get:(_,p)=>{let inherited=nodeRef.deref().closest(`[ajxl-${p}]`)?.getAttribute(`ajxl-${p}`);return inherited?.toLowerCase()==="disinherit"?undefined:inherited}});for(let event of(node.ajxl.event??this.defaultEvents[node.tagName.toLowerCase()]??"click").split(/\s/g))node.addEventListener(event.startsWith(":")?`ajaxial${event}`:event,handleTrigger.bind(this,nodeRef));dispatch(node,"load")}}}));async function handleTrigger(source,event){if(source instanceof WeakRef)source=source.deref();if(event.type==="submit")event.preventDefault();if(+source.ajxl.debounce>0)try{await new Promise(((res,rej)=>{source.ajaxialDebounceAbort?.();source.ajaxialDebounceAbort=rej;setTimeout((()=>{res();delete source.ajaxialDebounceAbort}),+source.ajxl.debounce)}))}catch{return}let context={source:source,method:orDefault(this.methods,source.ajxl.method),targets:source.ajxl.target?source.getRootNode().querySelectorAll(source.ajxl.target):[source],params:{...JSON.parse(source.ajxl.params??"{}"),...source instanceof HTMLFormElement?Object.fromEntries(new FormData(source)):{}}};if(!dispatch(source,"trigger",context))return;source.setAttribute("ajxl-inflight","");let fragment=await(context.method?.(source.ajxl.path,source,context.params));source.removeAttribute("ajxl-inflight");for(let target of context.targets){let context={source:source,target:target,fragment:fragment,swapStrategy:orDefault(this.swapStrategies,source.ajxl.swap?.toLowerCase())};if(!dispatch(source,"swap",context))continue;if(!context.target||!context.fragment||!context.swapStrategy)continue;if(context.fragment instanceof Function){let swapTest=document.createRange().createContextualFragment("<p><t></t></p>");context.swapStrategy(swapTest.querySelector("t"),document.createElement("f"));context.fragment=context.fragment(swapTest.querySelector("f")?.closest("t")?target:target.parentElement);if(!context.fragment)continue}else context.fragment=context.fragment.cloneNode(true);let children=Array.from(context.fragment.children);context.swapStrategy(context.target,context.fragment);for(let child of children){child.setAttribute("ajxl-added","");setTimeout((()=>child.removeAttribute("ajxl-added")),+source.ajxl.settle??20);this.process(child)}}dispatch(source,"finish")}function dispatch(target,name,detail){return target.dispatchEvent(new CustomEvent(`ajaxial:${name}`,{detail:detail,bubbles:true,composed:true,cancelable:true}))}function request(method,query,path,source,params){const url=new URL(path,window.location.href);const mime=(query?null:source.ajxl.encoding)??this.requestEncodings[defaultKey];const body=query?undefined:this.requestEncodings[mime]?.(params);if(query)Object.entries(params).forEach((([k,v])=>url.searchParams.append(k,v)));return fetch(url,{method:method,body:body,headers:{"Content-Type":mime,...JSON.parse(source.ajxl.headers??"{}")}}).then((resp=>dispatch(source,`request${resp.ok?"Success":"Failure"}`,{source:source,response:resp,params:params})?resp.text():"")).then((body=>{let[converter,...params]=(source.ajxl.convert??this.responseConverters[defaultKey]).trim().split(/\s+/g);return this.responseConverters[converter.toLowerCase()]?.(body,...params)})).catch((error=>{if(!dispatch(source,"requestError",{source:source,error:error,params:params}))return;throw error}))}};