diff --git a/asserts.js b/asserts.js index 0da7d35..c9b9eee 100644 --- a/asserts.js +++ b/asserts.js @@ -735,6 +735,22 @@ return { inc, dec: DM['n'] }; } __assert(__tSubTarIncDec, [], { inc: 3, dec: 2 }, 'dmEx target ^inc/^dec updates current numeric target by one'); + function __tSubTarJsos() { + __reset(); + _dm.set('src', { a: 1, b: [2, 3] }); + const el = document.createElement('div'); + dmEx(el, 'data-m-ex:out^jsos@src', 'val'); + return DM['out']; + } + __assert(__tSubTarJsos, [], '{\n "a": 1,\n "b": [\n 2,\n 3\n ]\n}', 'dmEx target ^jsos precomputed flag applies JSON stringify to output'); + function __tSubTarWindowProp() { + __reset(); + _dm.set('title', 'dmax-test'); + const el = document.createElement('div'); + dmEx(el, 'data-m-ex:_window.document.title@title', 'val'); + return document.title; + } + __assert(__tSubTarWindowProp, [], 'dmax-test', 'dmEx target _window property written via precomputed _el'); function __tSubSignalSiModPathAndExpr() { __reset(); _dm.set('foo', { bar: 7 }); @@ -1369,6 +1385,42 @@ } finally { tplEl.remove(); el.remove() } } __assert(__tDumpExplicitTemplate, [], 2, 'dmIt +#tplId explicit template reference appends 2 clones') + function __tDumpSingleItemGrowth() { + __reset() + const el = document.createElement('ul') + const tpl = document.createElement('template') + tpl.innerHTML = '
  • item
  • ' + el.appendChild(tpl) + document.body.appendChild(el) + try { + _dm.set('items', ['a', 'b']) + dmIt(el, 'data-m-it@items') + const before = el.children.length + setSiAndNotifySubs('t', { root: 'items', path: null }, ['a', 'b', 'c']) + const after = el.children.length + const lastIdx = el.lastElementChild ? el.lastElementChild.getAttribute('data-idx') : null + return { before, after, lastIdx } + } finally { el.remove() } + } + __assert(__tDumpSingleItemGrowth, [], { before: 2, after: 3, lastIdx: '2' }, 'dmIt single-item growth fast path appends one node directly') + function __tDumpMultiItemGrowth() { + __reset() + const el = document.createElement('ul') + const tpl = document.createElement('template') + tpl.innerHTML = '
  • item
  • ' + el.appendChild(tpl) + document.body.appendChild(el) + try { + _dm.set('items', ['a']) + dmIt(el, 'data-m-it@items') + const before = el.children.length + setSiAndNotifySubs('t', { root: 'items', path: null }, ['a', 'b', 'c', 'd']) + const after = el.children.length + const idxs = Array.from(el.children).map(n => n.getAttribute('data-idx')) + return { before, after, idxs } + } finally { el.remove() } + } + __assert(__tDumpMultiItemGrowth, [], { before: 1, after: 4, idxs: ['0', '1', '2', '3'] }, 'dmIt multi-item growth uses fragment path') __assert(() => { __reset() _dm.set('user', { name: 'Ann' }) @@ -2189,6 +2241,44 @@ return { sameChild: from.firstElementChild === child, text: from.textContent } } __assert(__tMorphNoSkipsSubtree, [], { sameChild: true, text: 'keep2' }, 'data-m-no skips subtree morph') + function __tMorphTextOnlyFocused() { + const input = document.createElement('div') + input.setAttribute('class', 'cell') + input.textContent = 'old' + document.body.appendChild(input) + try { + input.focus() + const to = document.createElement('div') + to.setAttribute('class', 'cell') + to.textContent = 'new' + morph(input, to) + return { text: input.textContent, cls: input.getAttribute('class') } + } finally { input.remove() } + } + __assert(__tMorphTextOnlyFocused, [], { text: 'new', cls: 'cell' }, 'morph: text-only focused element still updates text via normal path') + function __tMorphTextOnlyAttrsDiffer() { + const from = document.createElement('span') + from.setAttribute('class', 'old') + from.textContent = 'old' + const to = document.createElement('span') + to.setAttribute('class', 'new') + to.textContent = 'new' + morph(from, to) + return { text: from.textContent, cls: from.getAttribute('class') } + } + __assert(__tMorphTextOnlyAttrsDiffer, [], { text: 'new', cls: 'new' }, 'morph: text-only with attr mismatch updates both attrs and text') + function __tMorphTextOnlyFastPath() { + const from = document.createElement('td') + from.setAttribute('class', 'cell') + from.textContent = '42' + const origText = from.firstChild + const to = document.createElement('td') + to.setAttribute('class', 'cell') + to.textContent = '99' + morph(from, to) + return { text: from.textContent, sameNode: from.firstChild === origText, cls: from.getAttribute('class') } + } + __assert(__tMorphTextOnlyFastPath, [], { text: '99', sameNode: true, cls: 'cell' }, 'morph: text-only fast path assigns nodeValue directly') function __tDmaxPatchElementsReplaceDiscardsFormState() { const container = document.createElement('div') container.innerHTML = '' diff --git a/dist/dmax.min.js b/dist/dmax.min.js index ea3c2be..f58ebde 100644 --- a/dist/dmax.min.js +++ b/dist/dmax.min.js @@ -1 +1 @@ -const indexFirst=(e,t,n=0)=>{let r,o=e.length;for(let l of t)(r=e.indexOf(l,n))>=0&&r{if(!e)return e;if(e.indexOf("-")<0)return CAMEL_NAMES.set(e,e),e;let t=CAMEL_NAMES.get(e);return t||(t=e.replace(/-+([a-zA-Z]?)/g,(e,t)=>t?t.toUpperCase():""),CAMEL_NAMES.set(e,t),KEBAB_NAMES.set(t,e),t)},camelToKebab=e=>{if(!e)return e;let t=KEBAB_NAMES.get(e);return t||(t=e.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),KEBAB_NAMES.set(e,t),CAMEL_NAMES.set(t,e),t)},MOD="^",TARG=":",TRIG="@",ADD="+",ALL=["^",":","@","+"],MODS=["^"],DOT=".",ID="#",NOT="!",BRACKET_OPEN="[",BRACKET_CLOSE="]",NAME_DELIMS=[".","["],SEL_LEADS="#.[*:",SSE_COMMENT=":",SI="s",EP=".",SP="_",M_WITH_SHAPE="with_shape",M_SHAPE_ONLY="shape_only",M_IMMEDIATE="immediate",M_NOTIMMEDIATE="notimmediate",M_ONCE="once",M_ALWAYS="always",M_DEBOUNCE="debounce",M_THROTTLE="throttle",M_PREVENT="prevent",M_AND="and",M_EQ="eq",M_NE="ne",M_LT="lt",M_GT="gt",M_LE="le",M_GE="ge",M_PR="pr",M_ATTRS="attrs",M_SI_V="si",M_EV_V="ev",M_RW="rw",M_NUM="num",M_JSOS="jsos",M_JSON="json",M_TEXT="text",M_HTML="html",M_FORM="form",M_SSE="sse",M_BUSY="busy",M_COMPLETE="complete",M_ERR="err",M_CODE="code",M_STAT="stat",M_NO_CACHE="noCache",M_HS="hs",M_HS_NO_KEBAB="hsNoKebab",M_AUTH="auth",M_BROTLI="brotli",M_BR="br",M_GZIP="gzip",M_DEFLATE="deflate",M_COMPRESS="compress",M_REPLACE="replace",M_MERGE="merge",M_APPEND="append",M_PREPEND="prepend",M_BEFORE="before",M_AFTER="after",M_INNER="inner",M_REMOVE="remove",M_OUTER="outer",M_SSE_OPEN="open",M_SSE_CLOSE="close",M_RETRY="retry",M_ABORT="abort",M_URL="url",M_BODY="body",M_HDR="header",M_SPREAD="spread",M_SEND_ALL="sendAll",M_PATCH_ALL="patchAll",M_SYNC_ALL="syncAll",M_DEBOUNCE_MS=500,M_THROTTLE_MS=500,M_RETRY_MS=1e3,H_ACCEPT="accept",H_ACCEPT_ENCODING="accept-encoding",H_AUTHORIZATION="authorization",H_CACHE_CONTROL="cache-control",H_CONTENT_TYPE="content-type",H_PRAGMA="pragma",noProto=()=>Object.create(null),ACT_HS_EMPTY=Object.freeze(noProto()),ACT_HS_JSON=Object.freeze({[H_CONTENT_TYPE]:"application/json",[H_ACCEPT]:"application/json"}),ACT_HS_HTML=Object.freeze({[H_ACCEPT]:"text/html"}),ACT_HS_FORM=Object.freeze({[H_CONTENT_TYPE]:"application/x-www-form-urlencoded"}),ACT_HS_TEXT=Object.freeze({[H_CONTENT_TYPE]:"text/plain;charset=UTF-8"}),ACT_HS_NO_CACHE=Object.freeze({[H_CACHE_CONTROL]:"no-cache",[H_PRAGMA]:"no-cache"}),ACT_HS_SSE=Object.freeze({[H_ACCEPT]:"text/event-stream",[H_CACHE_CONTROL]:"no-cache",[H_PRAGMA]:"no-cache"}),SP_WIN="window",SP_DOC="document",SP_FORM="form",SP_INTERVAL="interval",SP_TIMEOUT="timeout",SP_VIEWED="viewed",SP_INIT="init",SPS=[SP_WIN,SP_DOC,"form","interval","timeout","viewed","init"],SP_WIN_EV="resize",SP_DOC_EV="visibilitychange",SP_INTERVAL_MS=500,SP_TIMEOUT_MS=500,SP_TA_WIN=1,SP_TA_DOC=2,SP_TA_FORM=3,SP_DEFS=Object.assign(noProto(),{[SP_WIN]:{ta:1,ev:"resize"},[SP_DOC]:{ta:2,ev:SP_DOC_EV},[SP_FORM]:{ta:3,ev:"submit",immediate:1},[SP_INTERVAL]:{ms:500,repeat:1},[SP_TIMEOUT]:{ms:500},[SP_VIEWED]:{io:1},[SP_INIT]:{init:1,act:1}}),ACT_METHODS=Object.freeze({get:"GET",post:"POST",put:"PUT",patch:"PATCH",delete:"DELETE"}),DM_KEY="data-m-",DM_NO="data-m-no",DM_NO_SCAN=DM_NO+"^scan",DM_NO_MORPH=DM_NO+"^morph",E_RW_REQ="dmEx ^rw requires an element/property trigger in:",E_RW_EL="dmEx ^rw source element is not found in trigger:",E_RW_EV="dmEx ^rw event is not found in trigger:",E_TRIG_EL="Element is not found in trigger:",E_TRIG_EV="Event is not found in trigger:",E_FORM_EL="Form element is not found for trigger:",IT_STATES=new WeakMap,IT_ATTRS=new WeakMap,isSp=e=>{if(e.startsWith(SP))for(const t of SPS)if(e.startsWith(t,1))return!0;return!1},mkIt=(e,t,n,r,o=NIL)=>({kind:e,not:t,root:n,path:r,mods:o,sp:e===SP&&SP_DEFS[n]||null,isSi:e===SI,isEv:e===EP,isSp:e===SP,isImmediate:null}),mkMod=(e,t,n)=>({kind:"^",not:e,root:t,path:n,isImmediate:"immediate"===t||"notimmediate"!==t&&null}),DEFAULT_PR_TA=Object.freeze(mkIt(EP,null,"",null)),RE_DIGITS=/^\d+$/,parseRef=(e,t,n=0)=>{if(!t)return null;let r=n,o=t.length;for(;t.startsWith("!",r);)++r;let l=0==r?null:r%2!=0,s=indexFirst(t,NAME_DELIMS,r),i=s<0?0==r?t:t.slice(r):t.slice(r,s),a=EP;if(i&&i.length>0){const n=i[0]===ID;if(n||isSp(i)){if(a=n?EP:SP,i=i.slice(1),!i)return logErr("empty",a+":",t,e),null}else a=SI,i=kebabToCamel(i)}if(s<0&&!i&&null!==l)return logErr("bare","!:",t),null;if(s<0||"."===t[s]&&s+1==o)return mkIt(a,l,i,null);r=s;let u=[];for(;r>=0&&r{if(!t)return null;let n=0,r=t.length;for(;t.startsWith("!",n);)++n;let o=0==n?null:n%2!=0;const l=indexFirst(t,NAME_DELIMS,n);let s=l<0?0==n?t:t.slice(n):t.slice(n,l);if(s&&(s=kebabToCamel(s)),!s)return logErr("empty mod:",t,e),null;if("attrs"===s){if(l<0||l+1>=r)return mkMod(o,s,{r:"",v:""});const n=t.slice(l+1);if(n[0]!==ID)return mkMod(o,s,{r:"",v:n});const i=n.indexOf(".",1),a=n.slice(1,i<0?n.length:i);return a?mkMod(o,s,{r:a,v:i<0?"":n.slice(i+1)}):(logErr("empty attrs mod:",t,e),null)}return mkMod(o,s,l<0||l+1>=r?null:t.indexOf(".",n=l+1)<0?kebabToCamel(t.slice(n)):parseRef(e,t,n))},parse=(e,t)=>{t??=5;const n=e.length,r=noProto();for(r["^"]=r[":"]=r["@"]=r["+"]=NIL;t>=0&&t{let t=_parseCache.get(e);return t||_parseCache.set(e,t=parse(e)[0]),t},RETURN_THEN=[" ","(","{",";","[",'"',"'","\n","\r","\t"],FN_ARGS=["dm","el","trig","val","detail"],_compiledFnCache=new Map,compileFn=(e,t,n=FN_ARGS)=>{const r=n===FN_ARGS?e+"\0"+t:null;if(null!==r&&_compiledFnCache.has(r))return _compiledFnCache.get(r);let o=""+e;const l=o.indexOf("return");let s,i=l>=0&&(l+6>=o.length||indexFirst(o,RETURN_THEN,l+6)==l+6)?o:`return(${o})`;i=`try{ ${i} }catch(e){ console.error('[dmax]','eval ${t}:',e.message,${o}); return }`;try{s=Function(...n,i)}catch(e){return void logErr(`compile ${t}:`,e.message,o)}return null!==r&&_compiledFnCache.set(r,s),s},_dm=new Map,DM=new Proxy({},{get:(e,t)=>_dm.get(t),set:(e,t,n)=>(_dm.set(t,n),!0),has:(e,t)=>_dm.has(t),ownKeys:()=>Array.from(_dm.keys()),getOwnPropertyDescriptor:(e,t)=>_dm.has(t)?{value:_dm.get(t),enumerable:!0,configurable:!0}:void 0}),dmSi=(e,t,n)=>{const r=parseCached(t),o=r[":"];(r["^"].length||r["@"].length||r["+"].length)&&warn("targets only:",t);let l=compileFn(n,t);if(!l)return;let s=n?l(DM,e,null):null;if(o.length)for(const e of o)e.kind==SI?(e.mods.length&&warn("mods ignored:",e.mods,t),_dm.set(e.root,s)):logErr("signal targets only:",e,t);else{if(!s||"object"!=typeof s)return logErr("object value expected:",t,n);for(const e in s)_dm.set(kebabToCamel(e),s[e])}},dmDbg=e=>{e&&(_debugEls.add(e),updateDebug())},getElById=(e,t)=>{const n=document.getElementById(e);return n||logErr(`no #${e}:`,t),n},getDefaultPr=e=>{const t=e.type,n=e.tagName;return"checkbox"===t||"radio"===t?"checked":"DETAILS"===n?"open":"INPUT"===n||"SELECT"===n||"TEXTAREA"===n?"value":"textContent"},getDefaultEv=e=>{const t=e.tagName;return"FORM"===t?"submit":"DETAILS"===t?"toggle":"INPUT"===t||"SELECT"===t||"TEXTAREA"===t?"change":"click"},getElPrVal=(e,t)=>{if(!e)return null;const n=t&&t.length?t[0]:getDefaultPr(e);let r=e[n];return void 0===r&&e.getAttribute&&(r=e.getAttribute(camelToKebab(n))),t&&t.length>1?getPrValAndDepth(r,t,-1,1)[0]:r},isDefaultPrName=(e,t)=>t===getDefaultPr(e)||"value"===t||"checked"===t||"textContent"===t,mkEv=e=>{try{return new Event(e,{bubbles:!0})}catch(t){const n=document.createEvent("Event");return n.initEvent(e,!0,!0),n}},isNil=e=>null==e,getPrValAndDepth=(e,t,n=-1,r=0)=>{let o=e;if(isNil(o)||!t)return[o,0];let l=-1==n||n>t.length-r?t.length-r:n;for(let e=0;e{if(n>=32)return console.warn("[dmax] Warning: too deep to compare for signal value change, consider it changed, stopped at:",32),!0;const r=e,o=t;if(Array.isArray(r)){if(!Array.isArray(o)||r.length!=o.length)return!0;for(let e=0;e{if(!n.isEv)return null;let o=n.root?getElById(n.root,t):e;const l=n.path;let s=l?null:getDefaultPr(o);if(l&&l.length&&([o]=getPrValAndDepth(o,l,l.length-1),s=l.at(-1)),!o||!s)return logErr("Error setting non existing property for:",n,"in",t);try{if("style"===s&&isPlainObj(r)&&o[s])for(const e in r){const t=o[s],n=r[e],l="-"===e[0]?e:"--"+camelToKebab(e);e in t?valChangedDeep(t[e],n)&&(t[e]=n):t.getPropertyValue(l)!==""+n&&t.setProperty(l,n)}else if(o&&"function"==typeof o.setProperty&&!(s in o)){const e="-"===s[0]?s:"--"+camelToKebab(s);o.getPropertyValue(e)!==""+r&&o.setProperty(e,r)}else valChangedDeep(o[s],r)&&(o[s]=r)}catch(t){logErr("Error: Failed to set property:",t.message,">>>",n,"on",e)}return o[s]},getComputedDisplay=e=>"undefined"!=typeof window&&window.getComputedStyle?window.getComputedStyle(e).display:"",applyClVal=(e,t,n)=>{for(const r of e){const e=r.kb||(r.kb=camelToKebab(r.root));(r.not?!n:n)?t.classList.add(e):t.classList.remove(e)}},applyDisplayValue=(e,t,n,r)=>{const o=e.style.display;r?t||"none"===o||"none"===getComputedDisplay(e)?e.style.display=n:e.style.removeProperty("display"):"none"!==o&&(e.style.display="none")},diffShapeShallow=(e,t)=>{let n=e,r=t;if(n&&"object"==typeof n||(n=NIL),r&&"object"==typeof r||(r=NIL),Array.isArray(n)){if(Array.isArray(r)){const e=r.length,t=n.length;return e==t?null:e>t?{addedRange:[t,e-t]}:{removedRange:[e,t-e]}}let e=[];for(const t in r)hasOwn(r,t)&&e.push(t);return{added:e,removedRange:[0,n.length]}}if(Array.isArray(r)){let e=[];for(const t in n)hasOwn(n,t)&&e.push(t);return{removed:e,addedRange:[0,r.length]}}let o=[],l=[];for(const e in r)e in n||o.push(e);for(const e in n)e in r||l.push(e);return o.length?l.length?{added:o,removed:l}:{added:o}:l.length?{removed:l}:null},samePath=(e,t)=>{if(e.length!==t.length)return!1;for(let n=0;ne.length?e:t,modPath=e=>null==e?NIL:e.kind?e.root?e.path?.length?[e.root,...e.path]:[e.root]:e.path||NIL:Array.isArray(e)?e:[e],compileMods=(e,t)=>{const n=null!=e.sp?.ms;let r=0,o=0,l=0,s=null,i=NIL,a=0,u=0,c="",d=null;for(const e of t){const t=e.root;if("with_shape"===t)a=1;else if("shape_only"===t)a=2;else if("pr"===t){const t=e.path;u=1,c=t?.isEv&&t.root||"",i=t?.isEv?t.path||NIL:modPath(t)}else"attrs"===t?(u=4,c=e.path?.r||"",i=e.path?.v||""):"si"===t?(u=2,i=modPath(e.path)):"ev"===t?(u=3,i=modPath(e.path)):"once"===t?r|=1:"always"===t?r|=2:"prevent"===t?r|=4:"num"===t?r|=8:"jsos"===t?d=e.path??2:"rw"===t?r|=16:n||"debounce"!==t?n||"throttle"!==t?t in PERMIT_MODS&&(s=s?s.push?(s.push(e),s):[s,e]:e):l=+(resolveMPathVal(e.path)??500)||500:o=+(resolveMPathVal(e.path)??500)||500}return{f:r,d:o,t:l,p:s,v:i,c:a,s:u,r:c,j:d}},getTrPrTa=(e,t,n,r,o,l,s=!0)=>{const i=n.root?getElById(n.root,t):e;if(!i)return logErr("Error:",o,n,"in:",t),null;let a=n.path?n.path[0]:null,u=null;a&&isDefaultPrName(i,a)&&(u=n.path,a=getDefaultEv(i));const c=1!==r.s&&4!==r.s||!r.r?i:getElById(r.r,t),d=1===r.s?r.v.length?r.v:u:4===r.s?r.v:u;return s&&1===r.s&&!r.r&&r.v.length&&(u=r.v),a=a??getDefaultEv(i),a?c?{taEl:i,readEl:c,ev:a,prPath:u,readPath:d,tar:mkIt(EP,null,n.root,u,NIL)}:logErr("Error:",o,n,"in:",t):(logErr("Error:",l,n,"in:",t),null)},addNonSiTrSub=(e,t,n,r,o,l,s=null)=>{const i=t.sp,a=!!i;if(!a&&!expected(s,"Expected non-SP trigger target in addNonSiTrSub:",t,"on:",e))return null;const u=addTrSub(e,t,n,r,o,a?null:s.taEl,a?t.path?.[0]||i?.ev||null:s.ev,a?null:s.prPath,a?null:s.readPath,a?null:s.readEl);return i?.init?(u&&!l&&invokeSub(u,{type:"init"},1===n.s||4===n.s?getReadVal(n.r?getElById(n.r):e,n,1===n.s?n.v.length?n.v:null:n.v):"init",e,t),!0):!u||l||!t.isImmediate||i&&!i.immediate?l:(invokeSub(u,null,a?null:getReadVal(s.readEl,n,s.readPath),e,t),!0)},PERMIT_MODS=Object.assign(noProto(),{[M_AND]:1,[M_EQ]:1,[M_NE]:1,[M_LT]:1,[M_GT]:1,[M_LE]:1,[M_GE]:1}),getSiVal=e=>{const t=_dm.get(e.root),n=e.path;return n?getPrValAndDepth(t,n)[0]:t},getSiValOrIt=e=>{if(!e.kind)return e;const t=getSiVal(e);return e.not?!t:t},resolveMPathVal=e=>{if(e&&e.kind)return getSiValOrIt(e);if("string"!=typeof e)return e;if(_dm.has(e))return _dm.get(e);const t=parseRef("mod",e);return t&&t.kind&&(!t.isSi||t.path||_dm.has(t.root))?getSiValOrIt(t):e},dmJsos=(e,t=2)=>"string"==typeof e?e:JSON.stringify(e,null,+(resolveMPathVal(t)??2)||0),resolveHtmlSelector=e=>{const t=resolveMPathVal(e);return"string"==typeof t&&t?"#.[*:".includes(t[0])?t:"#"+t:""},mkOrStatSi=(e,t)=>{if(!e)return null;const n=e.path;return"string"==typeof n?mkIt(SI,null,n||t,null):n?.isSi?n:mkIt(SI,null,t,null)},mkStatTar=(e,t,n)=>({root:e,path:t?t.concat(n):[n]}),defStatSi=e=>{if(!e)return null;let t=_dm.get(e.root);t&&"object"==typeof t||_dm.set(e.root,t=noProto());let n=t;const r=e.path;if(r&&r.length)for(let e=0;e{const t=defStatSi(mkOrStatSi(e,"stat"));if(!t)return null;const{root:n,path:r}=t;return{[M_BUSY]:mkStatTar(n,r,"busy"),[M_COMPLETE]:mkStatTar(n,r,"complete"),[M_ERR]:mkStatTar(n,r,"err"),[M_CODE]:mkStatTar(n,r,"code"),[M_SSE_OPEN]:mkStatTar(n,r,"open"),[M_SSE_CLOSE]:mkStatTar(n,r,"close"),[M_ABORT]:mkStatTar(n,r,"abort")}},isJsonContentType=e=>{const t=(e||"").toLowerCase();if(t.indexOf("application/json")>=0)return!0;const n=t.indexOf("+json");if(n<0)return!1;const r=n+5;if(r>=t.length)return!0;const o=t[r];return";"===o||" "===o||"\t"===o},isPlainObj=e=>!!e&&"object"==typeof e&&!Array.isArray(e),hasOwn=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),cloneOwnProps=e=>{const t=noProto();for(const n in e)hasOwn(e,n)&&(t[n]=e[n]);return t},mergeActHs=(e,t)=>{if(!e||e===ACT_HS_EMPTY)return t||ACT_HS_EMPTY;if(!t||t===ACT_HS_EMPTY)return e;const n=cloneOwnProps(e);for(const e in t)hasOwn(t,e)&&(n[e]=t[e]);return Object.freeze(n)},buildActBaseHs=(e,t,n,r,o,l,s)=>{let i=e?ACT_HS_JSON:r?ACT_HS_FORM:t?ACT_HS_TEXT:ACT_HS_EMPTY;if(n&&(i=mergeActHs(i,ACT_HS_HTML)),i=o?mergeActHs(i,ACT_HS_SSE):l?mergeActHs(i,ACT_HS_NO_CACHE):i,!s)return i;const a=i===ACT_HS_EMPTY?noProto():cloneOwnProps(i);return a["accept-encoding"]=s,Object.freeze(a)},isDigitsOnly=e=>"string"==typeof e&&RE_DIGITS.test(e),buildItRefBase=(e,t)=>{let n=e;if(t)for(let e=0;e{let n="dm."+e;if(t)for(let e=0;ebuildItRefBase(e,t)+"."+n,buildItItemExpr=(e,t,n)=>buildItExprBase(e,t)+"["+n+"]",replaceItTokens=(e,t,n)=>{if("string"!=typeof e)return e;let r=e.indexOf("$");if(r<0)return e;const o=[];let l=0;for(;r>=0;){const s=e.startsWith("$it",r)?t:e.startsWith("$ix",r)?n:null;s?(o.push(e.slice(l,r),s),l=r+3,r=e.indexOf("$",l)):r=e.indexOf("$",r+1)}return o.length?o.join("")+e.slice(l):e},rewriteItBindings=(e,t,n,r)=>{const o=[e];for(;o.length;){const e=o.pop(),l=e.attributes;let s=null;for(let e=l.length-1;e>=0;--e){const o=l[e],i=replaceItTokens(o.name,t,r),a=replaceItTokens(o.value,n,r);if(i!==o.name||a!==o.value){if(!s){s=[];for(let t=l.length-1;t>e;--t)s.push([l[t].name,l[t].value])}i===o.name&&(o.value=a)}s&&s.push([i,a])}s&&IT_ATTRS.set(e,s);const i=e.children;for(let e=i.length-1;e>=0;--e)o.push(i[e])}},noScan=e=>e&&e.hasAttribute&&(e.hasAttribute(DM_NO)||e.hasAttribute(DM_NO_SCAN)),noMorph=e=>e&&e.hasAttribute&&(e.hasAttribute(DM_NO)||e.hasAttribute(DM_NO_MORPH)),warn=(...e)=>console.warn("[dmax]",...e),logErr=(...e)=>console.error("[dmax]",...e),wireItClone=e=>{const t=[e];for(;t.length;){const e=t.pop();if(noScan(e))continue;const n=IT_ATTRS.get(e);if(n&&n.length)for(let t=0;t=0;--e)t.push(r[e])}},expected=(e,...t)=>e||(warn(...t),null),renderItState=(e,t,n,r,o,l)=>{const s=getSiValOrIt(t);if(!expected(Array.isArray(s),"dmIt expected array value from:",t,"on:",e))return;const i=s.length,a=n.count||0;if(ia){const t=document.createDocumentFragment();for(let e=a;e{if(Array.isArray(e)&&Array.isArray(t))return e.concat(t);if(!isPlainObj(e)||!isPlainObj(t))return t;const n=noProto();for(const t in e)hasOwn(e,t)&&(n[t]=e[t]);for(const e in t)hasOwn(t,e)&&(n[e]=hasOwn(n,e)?mergeActVals(n[e],t[e]):t[e]);return n},combineActResult=(e,t,n)=>"merge"===n?mergeActVals(e,t):"append"===n?Array.isArray(e)&&Array.isArray(t)?e.concat(t):"string"==typeof e||"string"==typeof t?""+(e??"")+(t??""):t:"prepend"===n?Array.isArray(e)&&Array.isArray(t)?t.concat(e):"string"==typeof e||"string"==typeof t?""+(t??"")+(e??""):t:t,getWriteMode=e=>{for(const t of e||NIL)if("replace"===t.root||"merge"===t.root||"append"===t.root||"prepend"===t.root)return t.root;return"replace"},patchMatchingSis=(e,t,n)=>{if(isPlainObj(t))for(const r in t){if(!hasOwn(t,r))continue;const o=kebabToCamel(r);if(!_dm.has(o))continue;const l=_dm.get(o);setSiAndNotifySubsNDeep(e,mkIt(SI,null,o,null),combineActResult(l,t[r],n))}},applyActPayload=(e,t,n,r)=>{if(!t)return;const o=getSiValOrIt(t);setSiAndNotifySubsNDeep(e,t,combineActResult(o,n,r))},permitVal=(e,t,n=e.root,r=resolveMPathVal(e.path))=>"and"===n?!!r!=!!e.not:"eq"==n?t==r:"ne"==n?t!=r:"gt"==n?+t>+r:"lt"==n?+t<+r:"ge"==n?+t>=+r:+t<=+r,modsPermitVal=(e,t)=>e.push?!e.some(e=>!permitVal(e,t)):permitVal(e,t),_subs=new Map,_debugEls=new Set;let _debugQueued=!1;const upsert=(e,t)=>{let n=e.get(t);return n||e.set(t,n=[]),n},removeSiSub=e=>{const t=_subs.get(e.trig.root);if(t&&t.length)for(let n=0;n{const t=e.trig.sp;t?.io?e.clearId.disconnect():t?.repeat?clearInterval(e.clearId):clearTimeout(e.clearId),e.clearId=null},removeSubOrClearId=e=>{try{const t=e.ev;t?t.taEl.removeEventListener(t.evName,e.fn,t.opts):null!=e.clearId?clearSubId(e):removeSiSub(e)}catch(e){}},PASSIVE_LISTENER_OPTS=Object.freeze({passive:!0}),ELEMENT_NODE=1,invokeSub=(e,t,n,r,o)=>e(DM,r,o,o.isSi?getSiVal(o):n,t),invokeBoundSub=(e,t=null)=>e.fn(DM,e.el,e.trig,e.trig.isSi?getSiVal(e.trig):null,t),onIntervalSub=e=>{const t={tick:e.tick++,ms:e.ms,type:"interval"};try{invokeSub(e.fn,t,e.ms,e.el,e.trig)}catch(t){logErr(`Error: interval handler (${e.ms}ms) failed:`,t?.message??t)}},onTimeoutSub=e=>{try{invokeSub(e.fn,{tick:0,ms:e.ms,type:"timeout"},e.ms,e.el,e.trig)}catch(t){logErr(`timeout ${e.ms}ms:`,t?.message??t)}},getAttrs=(e,t="")=>{const n=[];if(!e)return n;const r=e.attributes||NIL;for(let e=0;e4===t.s?getAttrs(e,n):getElPrVal(e,n),addSpSub=(e,t,n,r,o,l,s)=>{if(null!=n.ms){const i=+s||n.ms,a={el:e,trig:t,fn:null,siChangeM:null,ev:null,clearId:null,ms:i,tick:0};return a.fn=applyTrMs(o,t,r,a),a.clearId=n.repeat?setInterval(onIntervalSub,i,a):setTimeout(onTimeoutSub,i,a),l.push(a),a.fn}if(n.io){if("undefined"==typeof IntersectionObserver)return warn("IntersectionObserver missing, skip _viewed:",e),null;const n={el:e,trig:t,fn:null,siChangeM:null,ev:null,clearId:null};n.fn=applyTrMs(o,t,r,n);const s=new IntersectionObserver(r=>{for(const o of r)if(o.isIntersecting)try{invokeSub(n.fn,{ratio:o.intersectionRatio,type:"viewed"},o.intersectionRatio,e,t)}catch(e){logErr("viewed handler:",e?.message??e)}});return s.observe(e),n.clearId=s,l.push(n),n.fn}if(n.init)return applyTrMs(o,t,r);const i=1===n.ta?window:2===n.ta?document:3===n.ta&&e&&e.closest?e.closest("form"):null,a=t.path?.[0]||n.ev||null;if(3===n.ta&&!i)return logErr("Error:",E_FORM_EL,t,"on:",e),null;if(!expected(i&&a,"Expected event target/name in addSpSub:",t,"on:",e))return null;const u=!(4&r.f)&&PASSIVE_LISTENER_OPTS,c={el:e,trig:t,fn:null,siChangeM:null,ev:{taEl:i,evName:a,opts:u},clearId:null},d=applyTrMs(o,t,r,c);return c.fn=n=>invokeSub(d,n,n?.type??null,e,t),i.addEventListener(a,c.fn,u),l.push(c),d},addTrSub=(e,t,n,r,o,l,s,i,a=i,u=l)=>{if(t.isSi){const l={el:e,trig:t,fn:r,siChangeM:n.c,ev:null,clearId:null};return l.fn=applyTrMs(r,t,n,l),upsert(_subs,t.root).push(l),(o||upsert(_cleanupBoundSubs,e)).push(l),l}const c=t.sp;if(c)return addSpSub(e,t,c,n,r,o,s);if(!expected(l&&s,"Expected event target/name in addTrSub:",t,"on:",e))return null;const d=!(4&n.f)&&PASSIVE_LISTENER_OPTS,p={el:e,trig:t,fn:null,siChangeM:null,ev:{taEl:l,evName:s,opts:d},clearId:null},f=applyTrMs(r,t,n,p);return p.fn=r=>invokeSub(f,r,getReadVal(u,n,a),e,t),l.addEventListener(s,p.fn,d),o.push(p),f},findFirstKind=(e,t)=>{for(let n=0;n{_debugEls.size&&!_debugQueued&&(_debugQueued=!0,queueMicrotask(()=>{_debugQueued=!1;const e=noProto();for(const[t,n]of _dm.entries())e[t]=n;const t=JSON.stringify(e,null,2);for(const e of _debugEls)e.textContent=t}))},setSiAndNotifySubs=(e,t,n)=>{const r=t?.root,o=t?.path;if(!r)return null;let l=_dm.get(r),s=l,i=l,a=0,u=null;if(o){if(!o.length)return null;for(i&&"object"==typeof i||_dm.set(r,i=l={});a{if(syncDepth++>MAX_SYNC_DEPTH)return logErr(`Error: Infinite loop detected for signal: ${t} (depth > ${MAX_SYNC_DEPTH}) in ${e}`);try{return setSiAndNotifySubs(0,t,n)}finally{syncDepth--}},applyTrMs=(e,t,n,r)=>{const o=t.isSi,l=n.v,s=n.d,i=n.t,a=n.p,u=n.f,c=1&u&&!(2&u)&&r,d=!o&&4&u,p=n.s,f=(2===p&&o||3===p&&!o)&&l.length,m=8&u,h=n.j;if(!(c||d||s||i||a||t.not||f||m||null!=h)&&(o||r||t.sp?.init))return e;let g=0,E=0,S=!1,_=null,T=null,M=null,b=null,A=null;const y=function(n,u,P,v,I){if(P=P||t,!S){if(d&&I?.preventDefault?.(),s)return A??=function(){S=!0;try{y(_,T,null,M,b)}finally{S=!1}},_=n,T=u,M=v,b=I,clearTimeout(g),void(g=setTimeout(A,s));if(i){const e=Date.now();if(e-E{const r=parseCached(t),o=r[":"],l=r["@"],s=r["^"];r["+"].length&&warn("targets/triggers/mods only:",t);const i=null!=n&&""+n;let a=i?compileFn(n,t):(e,t,n,r)=>r;if(i&&!a)return;const u=e?upsert(_cleanupBoundSubs,e):null;if(!o.length&&l.length){const n=[],r=[],o=[];for(const i of l){const l=pickMods(i.mods,s),a=compileMods(i,l);if(!(16&a.f)){n.push({tr:i,mod:a}),i.isSi&&o.push([i,getWriteMode(i.mods)]);continue}if(!i.isEv)return logErr("Error:",E_RW_REQ,t);const u=getTrPrTa(e,t,i,a,E_RW_EL,E_RW_EV);if(!u)return;r.push({tr:i,mod:a,w:getWriteMode(i.mods),taEl:u.taEl,readEl:u.readEl,ev:u.ev,prPath:u.prPath,readPath:u.readPath,tar:u.tar})}if(r.length&&n.length){let l=!1;const s=(n,o,l,s)=>{const i=a(n,e,o,l,s);for(const n of r)setPr(e,t,n.tar,combineActResult(getElPrVal(n.taEl,n.prPath),i,n.w))};for(const r of n){const n=r.tr,o=r.mod;if(n.isSi){const t=addTrSub(e,n,o,(e,t,n,r,o)=>s(e,n,r,o),u);l||0==n.isImmediate||(l=!0,invokeBoundSub(t))}else{if(!n.isEv&&!n.isSp)return logErr("Error: unsupported trigger kind",n.kind,"in",t);{const r=n.isEv?getTrPrTa(e,t,n,o,E_RW_EL,E_RW_EV):null;if(n.isEv&&!r)return;if(null==(l=addNonSiTrSub(e,n,o,(e,t,n,r,o)=>s(e,n,r,o),u,l,r)))return}}}if(o.length)for(const n of r){const r=addTrSub(e,n.tr,n.mod,(n,r,l,s,i)=>{const u=a(n,e,l,s,i);for(const e of o)setSiAndNotifySubsNDeep(t,e[0],combineActResult(getSiVal(e[0]),u,e[1]))},u,n.taEl,n.ev,n.prPath,n.readPath,n.readEl);0!=n.tr.isImmediate&&invokeSub(r,null,getReadVal(n.readEl,n.mod,n.readPath),e,n.tr)}return}}if(o.length){const e=a;a=(n,r,l,s,i)=>{const a=e(n,r,l,s,i);let u=null;try{for(const e of o){u=e;const n=getWriteMode(e.mods),o=e.mods&&e.mods.some(e=>"jsos"===e.root)?dmJsos(a):a,l=combineActResult(e.isSi?getSiVal(e):getElPrVal(e.root?getElById(e.root,t):r,e.path),o,n);e.isSi?setSiAndNotifySubsNDeep(t,e,l):setPr(r,t,e,l)}}catch(e){logErr("Error: setting target",u,"in",t,"ended with ex:",e)}}}if(!l.length)return void(i&&a(DM,e,null,null,null));let c=!1;for(const n of l){const r=pickMods(n.mods,s),o=compileMods(n,r);if(n.isSi){const t=addTrSub(e,n,o,a,u);c||0==n.isImmediate||(c=!0,invokeBoundSub(t));continue}if(!n.isEv&&!n.isSp)return logErr("Error: unsupported trigger kind",n.kind,"in",t);const l=n.isEv&&getTrPrTa(e,t,n,o,E_TRIG_EL,E_TRIG_EV,!1);if(n.isEv&&!l)return;if(null==(c=addNonSiTrSub(e,n,o,a,u,c,l)))return}},dmCl=(e,t,n)=>{const r=parseCached(t),o=r["+"],l=r[":"],s=r["@"],i=r["^"];if(!o.length)return logErr("Error: dmCl requires class names via + syntax in:",t);if(!s.length)return logErr("Error: dmCl requires at least one trigger in:",t);const a=findFirstKind(l,EP),u=a&&a.root?getElById(a.root,t):e;if(!u)return logErr("Error: dmCl target element not found in:",t);const c=n?compileFn(n,t):null;if(n&&!c)return;const d=upsert(_cleanupBoundSubs,e);for(const n of s){const r=pickMods(n.mods,i),l=compileMods(n,r);if(n.isSi){const t=addTrSub(e,n,l,(e,t,n,r,l)=>applyClVal(o,u,c?c(e,t,n,r,l):r),d);0!=n.isImmediate&&invokeBoundSub(t)}else{const r=n.isEv?getTrPrTa(e,t,n,l,E_TRIG_EL,E_TRIG_EV,!1):null;if(n.isEv&&!r)return;if(null==addNonSiTrSub(e,n,l,(t,r,l,s,i)=>applyClVal(o,u,!c||c(t,e,n,s,i)),d,!1,r))return}}},dmSh=(e,t,n)=>{const r=parseCached(t),o=r[":"],l=r["@"],s=r["^"];if(!l.length)return logErr("Error: dmSh requires at least one trigger in:",t);const i=findFirstKind(o,EP),a=i&&i.root?getElById(i.root,t):e;if(!a)return logErr("Error: dmSh target element not found in:",t);const u=a.style&&a.style.display||"",c=getComputedDisplay(a),d=u||("none"!==c&&c?c:"block"),p=n?compileFn(n,t):null;if(n&&!p)return;const f=upsert(_cleanupBoundSubs,e);for(const n of l){const r=pickMods(n.mods,s),o=compileMods(n,r);if(n.isSi){const t=addTrSub(e,n,o,(e,t,n,r,o)=>applyDisplayValue(a,u,d,p?p(e,t,n,r,o):r),f);0!=n.isImmediate&&invokeBoundSub(t)}else{const r=n.isEv?getTrPrTa(e,t,n,o,E_TRIG_EL,E_TRIG_EV,!1):null;if(n.isEv&&!r)return;if(null==addNonSiTrSub(e,n,o,(t,r,o,l,s)=>applyDisplayValue(a,u,d,!p||p(t,e,n,l,s)),f,!1,r))return}}},dataM={},wireNode=(e,t,n)=>{if(0!==t.indexOf(DM_KEY)||noScan(e))return;const r=t.slice(7),o=indexFirst(r,ALL,0),l=o>=0?r.slice(0,o):r,s=dataM[l];s&&s(e,t,n)},dmScan=(e=document.body)=>{const t=[e],n=[];for(let e=0;e{const n=parseCached(t),r=n["@"],o=n["+"],l=n["^"];if(!r.length)return logErr("Error: dmIt requires a signal trigger in:",t);const s=r[0];if(!s.isSi)return logErr("Error: dmIt trigger must be a signal in:",t);const i=pickMods(s.mods,l);let a=null;if(o.length&&o[0].isEv&&o[0].root&&(a=getElById(o[0].root,t)),a||(a=e.querySelector("template")),a&&a.parentNode===e&&a.parentNode.removeChild(a),!a)return logErr("Error: dmIt template not found for:",t);const u=a.content&&a.content.firstElementChild;if(!u)return logErr("Error: dmIt template root not found for:",t);let c=IT_STATES.get(e);c||IT_STATES.set(e,c={nodes:[],count:0});const d=buildItRefBase(s.root,s.path),p=buildItExprBase(s.root,s.path);addTrSub(e,s,compileMods(s,i),()=>renderItState(e,s,c,u,d,p),upsert(_cleanupBoundSubs,e)),(s.isImmediate??1)&&renderItState(e,s,c,u,d,p)},dmAct=(e,t,n)=>{const r=t.slice(7),o=indexFirst(r,ALL,0),l=ACT_METHODS[o>=0?r.slice(0,o):r];if(!l)return logErr("Error: dmAct: unrecognised method prefix in:",t);const s=parseCached(t),i=s[":"],a=s["@"],u=s["+"],c=s["^"],d=n?compileFn(n,t):null;if(n&&!d)return;const p=findFirstKind(i,SI);let f=null,m=!1,h=!1,g=!1,E=!1,S=!1,_=!1,T=!1,M=!1,b=!1,A=!1,y=null,P=null,v=!1,I=!1,N=!1,C="replace",O=null,D=null;const L=[],R=[],w=[];for(const e of c){const t=e.root;"json"===t?m=!0:"text"===t?h=!0:"html"===t?g=!0:"form"===t?E=!0:"sse"===t?_=S=!0:"noCache"===t?_=!0:"brotli"===t||"br"===t?T=!0:"gzip"===t?M=!0:"deflate"===t?b=!0:"compress"===t?A=!0:"hs"!==t||y?"hsNoKebab"===t?v=!0:"auth"!==t||P?"replace"===t||"merge"===t||"append"===t||"prepend"===t||"before"===t||"after"===t||"inner"===t||"remove"===t?(C=t,"merge"!==t&&(O=e)):"stat"!==t||f?"retry"!==t||D?"url"===t?L.push(e):"body"===t?R.push(e):t===M_HDR?w.push(e):"syncAll"===t?I=N=!0:I||"sendAll"!==t?N||"patchAll"!==t||(N=!0):I=!0:D=e:f=e:P=e:y=e}p&&p.mods&&(C=getWriteMode(p.mods));const x=mkActStats(f),k=y?.path,V=P?.path,H=D?+(resolveMPathVal(D.path)??1e3)||1e3:0;let B="";T&&(B="br"),M&&(B+=(B?", ":"")+"gzip"),b&&(B+=(B?", ":"")+"deflate"),A&&(B+=(B?", ":"")+"compress");const F=buildActBaseHs(m,h,g,E,S,_,B),j="GET"===l||"DELETE"===l;let W=null;for(const e of u){const n=e.path;e.key=(n?n.at(-1):e.root)||"value",e.isEv&&e.root&&(e.taEl=getElById(e.root,t));for(let t=0;tx&&setSiAndNotifySubsNDeep(t,x[e],n),U=async()=>{const n=d?d(DM,e,null,null,null):"";if(!n)return logErr("Error: dmAct: URL is empty in:",t);K("busy",!0),K("complete",!1),K("err",null),K("code",null);try{const r=noProto(),o=noProto(),s=j?r:o;if(I)for(const[e,t]of _dm.entries())o[e]=t;for(const t of u){const n=t.isEv?getElPrVal(t.taEl||e,t.path):getSiValOrIt(t);if(t.spread){if(n&&"object"==typeof n)for(const e in n)hasOwn(n,e)?s[e]=n[e]:s.value=n}else s[t.key]=n}for(const[e,t,n,l]of G)(e?o:r)[t]=l?getSiValOrIt(l):_dm.get(n);let a=n,c=a.includes("?");for(const e in r)a+=(c?"&":"?")+encodeURIComponent(e)+"="+encodeURIComponent(""+(r[e]??"")),c=!0;let d=ACT_HS_EMPTY,f=1;if(k){const e=resolveMPathVal(k);if(isPlainObj(e)){d=noProto(),f=0;for(const t in e)hasOwn(e,t)&&(d[v?t:camelToKebab(t)]=""+e[t])}}if(F!==ACT_HS_EMPTY)if(d===ACT_HS_EMPTY)d=F;else for(const e in F)hasOwn(F,e)&&(d[e]=F[e]);if(null!=V){const e=resolveMPathVal(V);null!=e&&(f&&(d=cloneOwnProps(d),f=0),d.authorization=""+e)}for(const[e,t,n]of Y){f&&(d=cloneOwnProps(d),f=0);const r=n?getSiValOrIt(n):_dm.get(t);d[e]=null!=r?""+r:""}let h=0,S=null;for(const e in o)hasOwn(o,e)&&(h||(S=e),h++);let _=null;if(h){const e=1===h?o[S]:o;if(E&&(isPlainObj(e)||Array.isArray(e))){const t=new URLSearchParams;if(Array.isArray(e))for(let n=0;nT.abort():null,K("abort",W);const M={method:l,headers:d};null!=_&&(M.body=_),T&&(M.signal=T.signal);const b=await window.fetch(a,M),A=b.headers?.get("content-type")||"",y=A.includes("text/event-stream");let P;if(y)b.body&&"function"==typeof b.body.getReader?P=await consumeSseStream(b.body,t,x):(K("open",!0),P=applySse(await b.text(),t),K("open",!1),K("close",!0));else if(g&&A.includes("text/html")){P=await b.text();const t=O?.root||"outer",n=O&&O.path,r=n?"":findFirstKind(i,EP)?.root??"",o=n?resolveHtmlSelector(n):"before"===t||"after"===t?e.id?"#"+e.id:"":"append"!==t&&"prepend"!==t||!r?"":"#"+r;applyPatchEls({[SSE_ELS]:P,selector:o,mode:t})}else P=isJsonContentType(A)?await b.json():await b.text(),applyActPayload(t,p,P,C),N&&patchMatchingSis(t,P,C);K("busy",!1),K("complete",!0),K("err",null),K("code",Number.isFinite(b.status)?b.status:null),K("abort",null),W=null,!(H>0&&y)||T&&T.signal.aborted||setTimeout(U,H)}catch(e){W=null;const t=e&&"AbortError"===e.name;K("abort",null),K("open",!1),K("busy",!1),K("complete",!0),t||(K("err",e&&e.message?e.message:""+e),K("code",Number.isFinite(e&&e.status)?e.status:null),logErr("dmAct fail:",e),H>0&&setTimeout(U,H))}};if(!a.length)return void U();const $=upsert(_cleanupBoundSubs,e);let J=!1;for(const n of a){if(!n.isSi&&!n.isEv&&!n.isSp)return logErr("dmAct bad trigger:",n.kind,t);if(n.isSp){if(!n.sp?.act)return logErr("Error: dmAct unsupported SP trigger",n.root,"in",t);J||(J=!0,U());continue}const r=pickMods(n.mods,c),o=compileMods(n,r);if(n.isSi){addTrSub(e,n,o,U,$),!J&&n.isImmediate&&(J=!0,U());continue}const l=n.root?getElById(n.root,t):e;if(!l)return logErr("Error: dmAct element not found in trigger:",n,"in:",t);const s=n.path?.[0]??getDefaultEv(l);if(!s)return logErr("Error: dmAct event not found in trigger:",n,"in:",t);const i=addTrSub(e,n,o,U,$,l,s,null,null,l);!J&&n.isImmediate&&(J=!0,invokeSub(i,null,getElPrVal(l,null),e,n))}},WC_TMPLS=new WeakSet,WC_INITS=new WeakSet,defWc=(e,t)=>{if(!t||t.indexOf("-")<0)return logErr("dmWc template expects custom-element name value:",t);if(customElements.get(t)||WC_TMPLS.has(e))return;WC_TMPLS.add(e);const n=(e.getAttribute("data-m-wc-props")||"").match(/[^,\s]+/g)||NIL,r=class extends HTMLElement{connectedCallback(){if(!WC_INITS.has(this)){WC_INITS.add(this),!this.firstElementChild&&e.content&&(this.appendChild(e.content.cloneNode(!0)),wireItClone(this));for(const e of n){let t=this["$"+e];hasOwn(this,e)&&(t=this[e],delete this[e]),void 0!==t&&(this[e]=t)}}}};for(const e of n)Object.defineProperty(r.prototype,e,{get(){return this["$"+e]},set(t){this["$"+e]=t,this.dispatchEvent(new CustomEvent(e,{detail:t})),this.firstElementChild&&this.firstElementChild.dispatchEvent(new CustomEvent(e,{detail:t}))}});customElements.define(t,r)},dmWc=(e,t,n)=>"TEMPLATE"===e.tagName?defWc(e,n&&n.trim()):logErr("Error: dmWc is template-only; use data-m-ex for WC host props in:",t),dmNo=()=>{};dataM.si=dmSi,dataM.ex=dmEx,dataM.it=dmIt,dataM.wc=dmWc,dataM.cl=dmCl,dataM.sh=dmSh,dataM.dbg=dmDbg,dataM.no=dmNo,dataM.get=dataM.post=dataM.put=dataM.patch=dataM.delete=dmAct;const sameKind=(e,t)=>e.nodeType===t.nodeType&&(1!==e.nodeType||(e.id&&t.id?e.id===t.id:e.tagName===t.tagName)),sameSlot=(e,t)=>e.nodeType===t.nodeType&&(1!==e.nodeType||(e.id||t.id?e.id===t.id:e.tagName===t.tagName)),_HTML_PARSE_TEMPLATE=document.createElement("template"),TEXT_NODE=3,_siSelCache=new Map,SI_BAD_SYMS=" \t\r\n#>+~:.[],|",getSimpleIdSelector=e=>{if(!e||"#"!==e[0])return null;const t=_siSelCache.get(e);if(void 0!==t)return t;for(let t=1;t1?e.slice(1):null;return _siSelCache.set(e,n),n},getPatchTars=(e,t=e&&getSimpleIdSelector(e),n=t&&document.getElementById(t))=>e?t?n?[n]:NIL:document.querySelectorAll(e):NIL,sameAttrs=(e,t)=>{const n=e.attributes,r=t.attributes,o=r.length;if(n.length!==o)return!1;for(let e=0;e{const n=t.attributes,r=e.attributes,o=n.length,l=r.length;if(l||o){if(l===o){let e=!0,t=!1;for(let l=0;l=0;n--)t.hasAttribute(r[n].name)||e.removeAttribute(r[n].name)}else for(let t=l-1;t>=0;t--)e.removeAttribute(r[t].name)}},morphChildren=(e,t)=>{let n=e.firstChild,r=t.firstChild;for(;n&&r&&sameSlot(n,r);){const e=n.nextSibling;morph(n,r),n=e,r=r.nextSibling}if(!n){for(;r;r=r.nextSibling)e.appendChild(r.cloneNode(!0));return}if(!r){for(;n;){const t=n.nextSibling;e.removeChild(n),n=t}return}let o=null,l=0;for(let e=n;e;e=e.nextSibling)1===e.nodeType&&e.id&&((o??=noProto())[e.id]=e,l=1);for(;r;r=r.nextSibling){let t=null,s=1===r.nodeType?r.id:"";if(s&&o&&(t=o[s]))delete o[s];else{for(;l&&n&&1===n.nodeType&&n.id&&o[n.id];)n=n.nextSibling;n&&sameKind(n,r)&&(t=n)}t?(t!==n?e.insertBefore(t,n||null):n=n.nextSibling,morph(t,r)):e.insertBefore(r.cloneNode(!0),n||null)}for(;n;){const t=n.nextSibling;e.removeChild(n),n=t}if(o)for(const t in o){const n=o[t];n.parentNode===e&&e.removeChild(n)}};let _morphActiveEl=null;const doneMorph=e=>e&&(_morphActiveEl=null),morph=(e,t)=>{const n=null===_morphActiveEl;if(n&&(_morphActiveEl=document.activeElement),3===e.nodeType&&3===t.nodeType)return e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue),doneMorph(n);if(1!==e.nodeType||1!==t.nodeType||noMorph(e)||noMorph(t))return doneMorph(n);if(e.tagName!==t.tagName)return e.parentNode&&e.parentNode.replaceChild(t.cloneNode(!0),e),doneMorph(n);const r=e.firstChild,o=t.firstChild,l=r&&o&&!r.nextSibling&&!o.nextSibling&&3===r.nodeType&&3===o.nodeType;if(sameAttrs(e,t)&&(!r&&!o||l&&r.nodeValue===o.nodeValue))return doneMorph(n);const s=e.tagName,i=e===_morphActiveEl;let a=-1,u=-1,c="none",d=null,p=-1;if(!i||"INPUT"!==s&&"TEXTAREA"!==s)i&&"SELECT"===s&&(d=e.value,p=e.selectedIndex);else try{a=e.selectionStart,u=e.selectionEnd,c=e.selectionDirection||"none"}catch(e){}const f=e.scrollTop,m=e.scrollLeft,h=f||m;if(updateAttrs(e,t),l?r.nodeValue!==o.nodeValue&&(r.nodeValue=o.nodeValue):(r||o)&&morphChildren(e,t),h&&(e.scrollTop!==f&&(e.scrollTop=f),e.scrollLeft!==m&&(e.scrollLeft=m)),i&&a>=0)try{e.setSelectionRange(a,u,c)}catch(e){}else i&&"SELECT"===s&&(e.value=d,e.value!==d&&p>=0&&p{if(!e)return NIL;const n=(t||"html").toLowerCase();if("html"===n){_HTML_PARSE_TEMPLATE.innerHTML=e;const t=_HTML_PARSE_TEMPLATE.content.firstElementChild;if(!t)return NIL;if(!t.nextElementSibling)return[t];const n=[t];for(let e=t.nextElementSibling;e;e=e.nextElementSibling)n.push(e);return n}const r="svg"===n?`${e}`:`${e}`,o=(new DOMParser).parseFromString(r,"svg"===n?"image/svg+xml":"application/xml").documentElement;return o?Array.from(o.children):[]},insertFragRelative=(e,t,n)=>{if(!e||!t||!t.length)return;const r=document.createDocumentFragment(),o="prepend"===n?e.firstChild||null:"before"===n?e:e.nextSibling;for(const e of t)r.appendChild(e.cloneNode(!0));"append"===n?e.appendChild(r):("prepend"===n?e:e.parentNode)?.insertBefore(r,o)},applyPatchPair=(e,t,n,r=!1)=>{if(e&&t)if("replace"===n)e.replaceWith(r?t:t.cloneNode(!0));else if("inner"===n){const n=e.cloneNode(!1);for(let e=t.firstChild;e;e=e.nextSibling)n.appendChild(e.cloneNode(!0));morphChildren(e,n)}else morph(e,t)},applyPatchEls=e=>{const t=(e.mode||"outer").toLowerCase(),n=e.selector?""+e.selector:"",r=e.namespace?""+e.namespace:"html",o=e[SSE_ELS]||"";if("replace"===t&&"html"===r&&o){const e=n&&getPatchTars(n),t=!n&&/^\s*<[^>]*\sid\s*=\s*(?:"([^"]+)"|'([^']+)')/i.exec(o),r=n?1===e.length&&e[0]:document.getElementById(t&&(t[1]||t[2]||""));if(r)return void(r.outerHTML=""+o)}const l=parseSseEls(o,r);if("remove"!==t)if("append"!==t&&"prepend"!==t&&"before"!==t&&"after"!==t){if(n){if(!l.length)return;const e=getPatchTars(n);if(1===e.length&&1===l.length)return void applyPatchPair(e[0],l[0],t,!0);const r=l[0];for(let n=0;n{if(null===t)return JSON_MERGE_DELETE;if(!isPlainObj(t))return t;const n=isPlainObj(e)?cloneOwnProps(e):noProto();for(const e in t)if(hasOwn(t,e)){const r=applyJsonMergePatch(n[e],t[e]);r===JSON_MERGE_DELETE?delete n[e]:n[e]=r}return n},applyPatchSigs=(e,t)=>{const n=t[SSE_SIS];if(!n)return;let r=null;try{r=JSON.parse(n)}catch(t){return logErr("Error: patch sigs in",e,"expect JSON but found invalid format")}if(!isPlainObj(r))return;const o="true"===(t.onlyIfMissing||"").toLowerCase();for(const t in r)if(hasOwn(r,t)){if(o&&_dm.has(t))continue;const n=applyJsonMergePatch(_dm.get(t),r[t]),l=mkIt(SI,null,t,null);n!==JSON_MERGE_DELETE?setSiAndNotifySubsNDeep(e,l,n):_dm.has(t)&&(setSiAndNotifySubsNDeep(e,l,void 0),_dm.delete(t),updateDebug())}},flushSse=(e,t,n)=>{const r=t[1],o=t[0];t[2]&&r&&("dm-elements"===o?(applyPatchEls(r),e.push({event:o,args:r})):"dm-signals"===o&&(applyPatchSigs(n,r),e.push({event:o,args:r}))),t[0]="message",t[1]=null,t[2]=!1},consumeSseLine=(e,t,n,r)=>{if(!e)return flushSse(n,t,r);if(":"===e[0])return;const o=e.indexOf(":"),l=o<0?e:e.slice(0,o);let s=o<0?"":e.slice(o+1);if(" "===s[0]&&(s=s.slice(1)),"event"===l)t[0]=s||"message";else if("data"===l){const e=s.indexOf(" ");if(e<0)return;const n=s.slice(0,e),r=s.slice(e+1),o=t[1]||(t[1]=noProto());t[2]=!0,o[n]?o[n]+="\n"+r:o[n]=r}},applySse=(e,t="dmax-sse")=>{if(!e)return NIL;const n=[],r=""+e,o=["message",null,!1],l=/\r$/;let s,i=0;for(;(s=r.indexOf("\n",i))>=0;)consumeSseLine(r.slice(i,s).replace(l,""),o,n,t),i=s+1;return i{if(!e||"function"!=typeof e.getReader)return NIL;const r=(e,r)=>n&&setSiAndNotifySubsNDeep(t,n[e],r),o=[],l=e.getReader(),s=new TextDecoder,i=["message",null,!1],a=/\r$/;let u="",c=!1;try{for(;;){const{done:e,value:n}=await l.read();if(e)break;let d;for(c||(c=!0,r("open",!0),r("close",!1)),u+=s.decode(n,{stream:!0});(d=u.indexOf("\n"))>=0;)consumeSseLine(u.slice(0,d).replace(a,""),i,o,t),u=u.slice(d+1)}const e=s.decode();e&&(u+=e),u&&consumeSseLine(u.replace(a,""),i,o,t),flushSse(o,i,t)}catch(e){return r("open",!1),r("err",e.message||""+e),logErr("SSE stream error:",e),o}return r("open",!1),r("close",!0),o};var applyDmaxPatchElements=applyPatchEls,applyDmaxPatchSigs=applyPatchSigs,applyDmaxSse=applySse,consumeDmaxSseStream=consumeSseStream;const cleanupBoundSubsDeep=e=>{if(!e||1!==e.nodeType)return;const t=[e];for(;t.length;){const e=t.pop(),n=_cleanupBoundSubs.get(e);if(n){for(const e of n)removeSubOrClearId(e);_cleanupBoundSubs.delete(e)}const r=e.children;for(let e=0;e{for(const t of e)for(const e of t.removedNodes)cleanupBoundSubsDeep(e)});observer.observe(document.body,{childList:!0,subtree:!0}); +const e=(e,t,n=0)=>{let r,o=e.length;for(let l of t)(r=e.indexOf(l,n))>=0&&r{if(!e)return e;if(e.indexOf("-")<0)return n.set(e,e),e;let t=n.get(e);return t||(t=e.replace(/-+([a-zA-Z]?)/g,(e,t)=>t?t.toUpperCase():""),n.set(e,t),r.set(t,e),t)},l=e=>{if(!e)return e;let t=r.get(e);return t||(t=e.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),r.set(e,t),n.set(t,e),t)},s="^",i=":",u="@",c="+",a=[s,i,u,c],f=".",d=[f,"["],h="s",m=f,p="_",g="and",y="eq",v="ne",b="lt",E="gt",S="le",w="ge",x="attrs",A="selAll",T="rw",I="jsos",C="busy",O="complete",N="err",k="code",j="stat",P="replace",M="merge",L="append",$="prepend",R="inc",z="before",D="after",W="inner",V="remove",q="outer",F="open",_="close",U="abort",B="accept",J="cache-control",H="content-type",X="pragma",G=()=>Object.create(null),K=Object.freeze(G()),Z=Object.freeze({[H]:"application/json",[B]:"application/json"}),Q=Object.freeze({[B]:"text/html"}),Y=Object.freeze({[H]:"application/x-www-form-urlencoded"}),ee=Object.freeze({[H]:"text/plain;charset=UTF-8"}),te=Object.freeze({[J]:"no-cache",[X]:"no-cache"}),ne=Object.freeze({[B]:"text/event-stream",[J]:"no-cache",[X]:"no-cache"}),re="window",oe="document",le="history",se="form",ie="interval",ue="timeout",ce="viewed",ae="init",fe=[re,oe,le,se,ie,ue,ce,ae],de=Object.assign(G(),{[re]:{ta:1,ev:"resize"},[oe]:{ta:2,ev:"visibilitychange"},[le]:{ta:"history"},[se]:{ta:3,ev:"submit",immediate:1},[ie]:{ms:500,repeat:1},[ue]:{ms:500},[ce]:{io:1},[ae]:{init:1,act:1}}),he=Object.freeze({get:"GET",post:"POST",put:"PUT",patch:"PATCH",delete:"DELETE"}),me="data-m-",pe=me+"no",ge=pe+"^scan",ye=pe+"^morph",ve=`dmEx ${s}${T} requires element/property trigger:`,be=`dmEx ${s}${T} element not found:`,Ee=`dmEx ${s}${T} event not found:`,Se="element not found:",we="event not found:",xe=new WeakMap,Ae=new WeakMap,Te=(e,n,r,o,l=t)=>({kind:e,not:n,root:r,path:o,mods:l,sp:e===p&&de[r]||null,isSi:e===h,isEv:e===m,isSp:e===p,isImmediate:null}),Ie=(e,t,n)=>({kind:s,not:e,root:t,path:n,isImmediate:"immediate"===t||"notImmediate"!==t&&null}),Ce=/^\d+$/,Oe=(t,n,r=0)=>{if(!n)return null;let l=r,s=n.length;for(;n.startsWith("!",l);)++l;let i=0==l?null:l%2!=0,u=e(n,d,l),c=u<0?0==l?n:n.slice(l):n.slice(l,u),a=m;if(c&&c.length>0){const e="#"===c[0];if(e||(e=>{if(e.startsWith(p))for(const t of fe)if(e.startsWith(t,1))return!0;return!1})(c)){if(a=e?m:p,c=c.slice(1),!c)return Et("empty",a+":",n,t),null}else a=h,c=o(c)}if(u<0&&!c&&null!==i)return Et("bare","!:",n),null;if(u<0||n[u]===f&&u+1==s)return Te(a,i,c,null);l=u;let g=[];for(;l>=0&&l{if(!n)return null;let r=0,l=n.length;for(;n.startsWith("!",r);)++r;let s=0==r?null:r%2!=0;const i=e(n,d,r);let u=i<0?0==r?n:n.slice(r):n.slice(r,i);if(u&&(u=o(u)),!u)return Et("empty mod:",n,t),null;if(u===x){if(i<0||i+1>=l)return Ie(s,u,{r:"",v:""});const e=n.slice(i+1);if("#"!==e[0])return Ie(s,u,{r:"",v:e});const r=e.indexOf(f,1),o=e.slice(1,r<0?e.length:r);return o?Ie(s,u,{r:o,v:r<0?"":e.slice(r+1)}):(Et("empty attrs mod:",n,t),null)}return Ie(s,u,"sel"===u||u===A?i<0||i+1>=l?"":n.slice(i+1):i<0||i+1>=l?null:n.indexOf(f,r=i+1)<0?o(n.slice(r)):Oe(t,n,r))},ke=new Map,je=n=>{let r=ke.get(n);return r||ke.set(n,r=((n,r)=>{r??=5;const o=n.length,l=G();for(l[s]=l[i]=l[u]=l[c]=t;r>=0&&r{const o=r===Me?t+"\0"+n:null;if(null!==o&&Le.has(o))return Le.get(o);let l=""+t;const s=l.indexOf("return");let i,u=s>=0&&(s+6>=l.length||e(l,Pe,s+6)==s+6)?l:`return(${l})`;u=`try{ ${u} }catch(e){ console.error('[dmax]','eval ${n}:',e.message,${l}); return }`;try{i=Function(...r,u)}catch(e){return void Et(`compile ${n}:`,e.message,l)}return null!==o&&Le.set(o,i),i},Re=new Map,ze=new Proxy({},{get:(e,t)=>Re.get(t),set:(e,t,n)=>(Re.set(t,n),!0),has:(e,t)=>Re.has(t),ownKeys:()=>Array.from(Re.keys()),getOwnPropertyDescriptor:(e,t)=>Re.has(t)?{value:Re.get(t),enumerable:!0,configurable:!0}:void 0}),De=(e,t)=>{const n=document.getElementById(e);return n||Et(`no #${e}:`,t),n},We=e=>{const t=e.type,n=e.tagName;return"checkbox"===t||"radio"===t?"checked":"DETAILS"===n?"open":"INPUT"===n||"SELECT"===n||"TEXTAREA"===n||n&&n.indexOf("-")>=0&&"value"in e?"value":"textContent"},Ve=e=>{const t=e.tagName;return"FORM"===t?"submit":"DETAILS"===t?"toggle":"INPUT"===t||"SELECT"===t||"TEXTAREA"===t?"change":"click"},qe=(e,t)=>{if(!e)return null;const n=t&&t.length?t[0]:We(e);let r=e[n];return void 0===r&&e.getAttribute&&(r=e.getAttribute(l(n))),t&&t.length>1?_e(r,t,-1,1)[0]:r},Fe=e=>null==e,_e=(e,t,n=-1,r=0)=>{let o=e;if(Fe(o)||!t)return[o,0];let l=-1==n||n>t.length-r?t.length-r:n;for(let e=0;e{if(n>=32)return console.warn("[dmax] deep compare limit:",32),!0;const r=e,o=t;if(Array.isArray(r)){if(!Array.isArray(o)||r.length!=o.length)return!0;for(let e=0;e{if(!n.isEv&&!n.isSp)return null;let o=n.isSp?n.root===re?window:n.root===oe?document:n.root===le?window.history:null:n.root?De(n.root,t):e;const s=n.path;let i=s?null:We(o);if(s&&s.length&&([o]=_e(o,s,s.length-1),i=s.at(-1)),!o||!i)return Et("setting non-existing prop:",n,"in",t);try{if("function"==typeof o[i])return Array.isArray(r)?o[i](...r):o[i](r);if("style"===i&&at(r)&&o[i])for(const e in r){const t=o[i],n=r[e],s="-"===e[0]?e:"--"+l(e);e in t?Ue(t[e],n)&&(t[e]=n):t.getPropertyValue(s)!==""+n&&t.setProperty(s,n)}else if(o&&"function"==typeof o.setProperty&&!(i in o)){const e="-"===i[0]?i:"--"+l(i);o.getPropertyValue(e)!==""+r&&o.setProperty(e,r)}else Ue(o[i],r)&&(o[i]=r)}catch(t){Et("Failed to set property:",t.message,">>>",n,"on",e)}return o[i]},Je=e=>"undefined"!=typeof window&&window.getComputedStyle?window.getComputedStyle(e).display:"",He=(e,t,n)=>{for(const r of e){const e=r.kb||(r.kb=l(r.root));(r.not?!n:n)?t.classList.add(e):t.classList.remove(e)}},Xe=(e,t,n,r)=>{const o=e.style.display;r?t||"none"===o||"none"===Je(e)?e.style.display=n:e.style.removeProperty("display"):"none"!==o&&(e.style.display="none")},Ge=(e,n)=>{let r=e,o=n;if(r&&"object"==typeof r||(r=t),o&&"object"==typeof o||(o=t),Array.isArray(r)){if(Array.isArray(o)){const e=o.length,t=r.length;return e==t?null:e>t?{addedRange:[t,e-t]}:{removedRange:[e,t-e]}}let e=[];for(const t in o)ft(o,t)&&e.push(t);return{added:e,removedRange:[0,r.length]}}if(Array.isArray(o)){let e=[];for(const t in r)ft(r,t)&&e.push(t);return{removed:e,addedRange:[0,o.length]}}let l=[],s=[];for(const e in o)e in r||l.push(e);for(const e in r)e in o||s.push(e);return l.length?s.length?{added:l,removed:s}:{added:l}:s.length?{removed:s}:null},Ke=(e,t)=>{if(e.length!==t.length)return!1;for(let n=0;nYe(e,e.mods.length?e.mods:t),Qe=e=>null==e?t:e.kind?e.root?e.path?.length?[e.root,...e.path]:[e.root]:e.path||t:Array.isArray(e)?e:[e],Ye=(e,n)=>{const r=null!=e.sp?.ms;let o=0,l=0,s=0,i=null,u=t,c=0,a=0,f="",d=null;for(const e of n){const n=e.root;if("with_shape"===n)c=1;else if("shape_only"===n)c=2;else if("pr"===n){const n=e.path;a=1,f=n?.isEv&&n.root||"",u=n?.isEv?n.path||t:Qe(n)}else n===x?(a=4,f=e.path?.r||"",u=e.path?.v||""):"sel"===n?(a=5,u=e.path||""):n===A?(a=6,u=e.path||""):"si"===n?(a=2,u=Qe(e.path)):"ev"===n?(a=3,u=Qe(e.path)):"once"===n?o|=1:"always"===n?o|=2:"prevent"===n?o|=4:"num"===n?o|=8:"raf"===n?o|=32:n===I?d=e.path??2:n===T?o|=16:r||"debounce"!==n?r||"throttle"!==n?n in nt&&(i=i?i.push?(i.push(e),i):[i,e]:e):s=+(lt(e.path)??500)||500:l=+(lt(e.path)??500)||500}return{f:o,d:l,t:s,p:i,v:u,c:c,s:a,r:f,j:d}},et=(e,n,r,o,l,s,i=!0)=>{const u=r.root?De(r.root,n):e;if(!u)return Et(l,r,"in:",n),null;let c=r.path?r.path[0]:null,a=null;c&&((e,t)=>t===We(e)||"value"===t||"checked"===t||"textContent"===t)(u,c)&&(a=r.path,c=Ve(u));const f=1!==o.s&&4!==o.s||!o.r?u:De(o.r,n),d=1===o.s||3===o.s?o.v.length?o.v:a:4===o.s||5===o.s||6===o.s?o.v:a;return i&&1===o.s&&!o.r&&o.v.length&&(a=o.v),c=c??Ve(u),c?f?{taEl:u,readEl:f,ev:c,prPath:a,readPath:d,tar:Te(m,null,r.root,a,t)}:Et(l,r,"in:",n):(Et(s,r,"in:",n),null)},tt=(e,t,n,r,o,l,s=null)=>{const i=t.sp,u=!!i;if(!u&&!wt(s,"Expected non-SP trigger target in addNonSiTrSub:",t,"on:",e))return null;const c=_t(e,t,n,r,o,u?null:s.taEl,u?t.path?.[0]||i?.ev||null:s.ev,u?null:s.prPath,u?null:s.readPath,u?null:s.readEl);return i?.init?(c&&!l&&Lt(c,{type:ae},1===n.s||4===n.s||5===n.s||6===n.s?qt(n.r?De(n.r):e,n,1===n.s?n.v.length?n.v:null:n.v):ae,e,t),!0):!c||l||!t.isImmediate||i&&!i.immediate?l:(Lt(c,null,u?null:qt(s.readEl,n,s.readPath),e,t),!0)},nt=Object.assign(G(),{[g]:1,[y]:1,[v]:1,[b]:1,[E]:1,[S]:1,[w]:1}),rt=e=>{const t=Re.get(e.root),n=e.path;return n?_e(t,n)[0]:t},ot=e=>{if(!e.kind)return e;const t=rt(e);return e.not?!t:t},lt=e=>{if(e&&e.kind)return ot(e);if("string"!=typeof e)return e;if(Re.has(e))return Re.get(e);const t=Oe("mod",e);return t&&t.kind&&(!t.isSi||t.path||Re.has(t.root))?ot(t):e},st=(e,t=2)=>"string"==typeof e?e:JSON.stringify(e,null,+(lt(t)??2)||0),it=(e,t,n)=>({root:e,path:t?t.concat(n):[n]}),ut=[C,O,F,_],ct=[N,k,U],at=e=>!!e&&"object"==typeof e&&!Array.isArray(e),ft=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),dt=e=>{const t=G();for(const n in e)ft(e,n)&&(t[n]=e[n]);return t},ht=(e,t)=>{if(!e||e===K)return t||K;if(!t||t===K)return e;const n=dt(e);for(const e in t)ft(t,e)&&(n[e]=t[e]);return Object.freeze(n)},mt=e=>"string"==typeof e&&Ce.test(e),pt=(e,t,n)=>{if("string"!=typeof e)return e;let r=e.indexOf("$");if(r<0)return e;const o=[];let l=0;for(;r>=0;){const s=e.startsWith("$it",r)?t:e.startsWith("$ix",r)?n:null;s?(o.push(e.slice(l,r),s),l=r+3,r=e.indexOf("$",l)):r=e.indexOf("$",r+1)}return o.length?o.join("")+e.slice(l):e},gt=(e,t,n,r)=>{const o=[e];for(;o.length;){const e=o.pop(),l=e.attributes;let s=null;for(let e=l.length-1;e>=0;--e){const o=l[e],i=pt(o.name,t,r),u=pt(o.value,n,r);if(i!==o.name||u!==o.value){if(!s){s=[];for(let t=l.length-1;t>e;--t)s.push([l[t].name,l[t].value])}i===o.name&&(o.value=u)}s&&s.push([i,u])}s&&Ae.set(e,s);const i=e.children;for(let e=i.length-1;e>=0;--e)o.push(i[e])}},yt=e=>e&&e.hasAttribute&&(e.hasAttribute(pe)||e.hasAttribute(ge)),vt=e=>e.hasAttribute(pe)||e.hasAttribute(ye),bt=(...e)=>console.warn("[dmax]",...e),Et=(...e)=>console.error("[dmax]",...e),St=e=>{const t=[e];for(;t.length;){const e=t.pop();if(yt(e))continue;const n=Ae.get(e);if(n&&n.length)for(let t=0;t=0;--e)t.push(r[e])}},wt=(e,...t)=>e||(bt(...t),null),xt=(e,t,n,r,o,l)=>{const s=ot(t);if(!wt(Array.isArray(s),"dmIt expected array value from:",t,"on:",e))return;const i=s.length,u=n.count||0;if(iu){const t=i-u;if(1===t){const t=r.cloneNode(!0),s=""+u;gt(t,o+"."+s,l+"["+s+"]",s),e.appendChild(t),n.nodes.push(t)}else{const t=document.createDocumentFragment();for(let e=u;e{if(Array.isArray(e)&&Array.isArray(t))return e.concat(t);if(!at(e)||!at(t))return t;const n=dt(e);for(const e in t)ft(t,e)&&(n[e]=ft(n,e)?At(n[e],t[e]):t[e]);return n},Tt=(e,t,n)=>{if(n===M)return At(e,t);if(n===R||"dec"===n)return(+e||0)+(n===R?1:-1);if(n===L||n===$){if(Array.isArray(e)&&Array.isArray(t))return n===L?e.concat(t):t.concat(e);if("string"==typeof e||"string"==typeof t)return n===L?""+(e??"")+(t??""):""+(t??"")+(e??"")}return t},It=e=>{for(const n of e||t)if(n.root===P||n.root===M||n.root===L||n.root===$||n.root===R||"dec"===n.root)return n.root;return P},Ct=(e,t,n=e.root,r=lt(e.path))=>"and"===n?!!r!=!!e.not:"eq"==n?t==r:"ne"==n?t!=r:"gt"==n?+t>+r:"lt"==n?+t<+r:"ge"==n?+t>=+r:+t<=+r,Ot=new Map,Nt=new Set;let kt=!1;const jt=(e,t)=>{let n=e.get(t);return n||e.set(t,n=[]),n},Pt=e=>{try{const t=e.ev;t?t.taEl.removeEventListener(t.evName,e.fn,t.opts):null!=e.clearId?(e=>{const t=e.trig.sp;t?.io?e.clearId.disconnect():t?.repeat?clearInterval(e.clearId):clearTimeout(e.clearId),e.clearId=null})(e):(e=>{const t=Ot.get(e.trig.root);if(t&&t.length)for(let n=0;ne(ze,r,o,o.isSi?rt(o):n,t),$t=(e,t=null)=>e.fn(ze,e.el,e.trig,e.trig.isSi?rt(e.trig):null,t),Rt=e=>{const t={tick:e.tick++,ms:e.ms,type:ie};try{Lt(e.fn,t,e.ms,e.el,e.trig)}catch(t){Et(`Error: interval handler (${e.ms}ms) failed:`,t?.message??t)}},zt=e=>{try{Lt(e.fn,{tick:0,ms:e.ms,type:ue},e.ms,e.el,e.trig)}catch(t){Et(`timeout ${e.ms}ms:`,t?.message??t)}},Dt=(e,t=e?.getRootNode?.()||e?.ownerDocument||document)=>(t===e&&e?.ownerDocument&&(t=e.ownerDocument),t&&"function"==typeof t.querySelectorAll?t:document),Wt=(e,t=document)=>t.querySelector(e||""),Vt=(e,t=document)=>Array.from(t.querySelectorAll(e||"")),qt=(e,n,r)=>4===n.s?((e,n="")=>{const r=[];if(!e)return r;const o=e.attributes||t;for(let e=0;e3===n.s?r?.length?qe(e,r):Xt(e):qt(t,n,r),_t=(e,t,n,r,o,s,i,u,c=u,a=s)=>{if(t.isSi){const l={el:e,trig:t,fn:r,siChangeM:n.c,ev:null,clearId:null};return l.fn=Gt(r,t,n,l),jt(Ot,t.root).push(l),(o||jt(Kt,e)).push(l),l}const f=t.sp;if(f)return((e,t,n,r,o,l,s)=>{if(null!=n.ms){const i=+s||n.ms,u={el:e,trig:t,fn:null,siChangeM:null,ev:null,clearId:null,ms:i,tick:0};return u.fn=Gt(o,t,r,u),u.clearId=n.repeat?setInterval(Rt,i,u):setTimeout(zt,i,u),l.push(u),u.fn}if(n.io){if("undefined"==typeof IntersectionObserver)return bt("no IntersectionObserver:",e),null;const n={el:e,trig:t,fn:null,siChangeM:null,ev:null,clearId:null};n.fn=Gt(o,t,r,n);const s=new IntersectionObserver(r=>{for(const o of r)if(o.isIntersecting)try{Lt(n.fn,{ratio:o.intersectionRatio,type:ce},o.intersectionRatio,e,t)}catch(e){Et("viewed handler:",e?.message??e)}});return s.observe(e),n.clearId=s,l.push(n),n.fn}if(n.init)return Gt(o,t,r);const i=1===n.ta?window:2===n.ta?document:3===n.ta&&e&&e.closest?e.closest("form"):null,u=t.path?.[0]||n.ev||null,c=1===r.s?r.v.length?r.v:null:4===r.s||5===r.s||6===r.s?r.v:null;if(3===n.ta&&!i)return Et("form element not found:",t,"on:",e),null;if(!wt(i&&u,"Expected event target/name in addSpSub:",t,"on:",e))return null;const a=!(4&r.f)&&Mt,f={el:e,trig:t,fn:null,siChangeM:null,ev:{taEl:i,evName:u,opts:a},clearId:null},d=Gt(o,t,r,f);return f.fn=n=>Lt(d,n,1===r.s||4===r.s||5===r.s||6===r.s||3===r.s?Ft(n,i,r,c):n?.type??null,e,t),i.addEventListener(u,f.fn,a),l.push(f),d})(e,t,f,n,r,o,i);if(!wt(s&&i,"Expected event target/name in addTrSub:",t,"on:",e))return null;const d=!(4&n.f)&&Mt,h=s?.tagName&&s.tagName.indexOf("-")>=0,m=h?l(i):i,p={el:e,trig:t,fn:null,siChangeM:null,ev:{taEl:s,evName:m,opts:d},clearId:null},g=Gt(r,t,n,p),y=!n.s&&!c&&h;return p.fn=r=>Lt(g,r,y?Xt(r):Ft(r,a,n,c),e,t),s.addEventListener(m,p.fn,d),o.push(p),g},Ut=(e,t)=>{for(let n=0;n{Nt.size&&!kt&&(kt=!0,queueMicrotask(()=>{kt=!1;const e=G();for(const[t,n]of Re.entries())e[t]=n;const t=JSON.stringify(e,null,2);for(const e of Nt)e.textContent=t}))};let Jt=0;const Ht=(e,t,n)=>{if(Jt++>32)return Et(`Error: Infinite loop detected for signal: ${t} (depth > 32) in ${e}`);try{return((e,t,n)=>{const r=t?.root,o=t?.path;if(!r)return null;let l=Re.get(r),s=l,i=l,u=0,c=null;if(o){if(!o.length)return null;for(i&&"object"==typeof i||Re.set(r,i=l={});uvoid 0===t?e:t&&"object"==typeof t?t.value??t.ms??t:t,Gt=(e,t,n,r)=>{const o=t.isSi,l=n.v,s=n.d,i=n.t,u=n.p,c=n.f,a=1&c&&!(2&c)&&r,f=!o&&4&c,d=32&c,h=n.s,m=(2===h&&o||3===h&&!o)&&l.length,p=8&c,g=n.j;if(!(a||f||s||i||d||u||t.not||m||p||null!=g)&&(o||r||t.sp?.init))return e;let y=0,v=0,b=!1,E=!1,S=!1,w=null,x=null,A=null,T=null,I=null,C=null,O=null,N=null,k=null,j=null;const P=function(n,c,M,L,$){if(M=M||t,!b){if(f&&$?.preventDefault?.(),s)return k??=function(){b=!0;try{P(w,x,null,A,T)}finally{b=!1}},w=n,x=c,A=L,T=$,clearTimeout(y),void(y=setTimeout(k,s));if(i){const e=Date.now();if(e-v{S=!1,E=!0;try{P(I,C,null,O,N)}finally{E=!1}},void(e=>{("function"==typeof requestAnimationFrame?requestAnimationFrame:setTimeout)(e,16)})(j)}}let R=o?L??rt(M):3===h?l.length?$:Xt($):L??Xt($);if(m&&(R=_e(R,l)[0]),p&&(R=null==R||""===R?null:+R),M.not&&(R=!R),!u||(D=R,(z=u).push?!z.some(e=>!Ct(e,D)):Ct(z,D))){var z,D;null!=g&&(R=st(R,g));try{e(n,c,M,R,$)}catch(e){Et("handler:",e)}a&&Pt(r)}};return P},Kt=new WeakMap,Zt={},Qt=(t,n,r)=>{if(0!==n.indexOf(me)||yt(t))return;const o=n.slice(7),l=e(o,a,0),s=l>=0?o.slice(0,l):o,i=Zt[s];i&&i(t,n,r)},Yt=()=>{};let en=Yt;const tn=(e,t)=>0===e.indexOf(me)?e:me+t+e,nn=(e,t)=>{if(!e||1!==e.nodeType)return Et("dm element expected:",e),Yt;const n=jt(Kt,e),r=n.length;if(t(e,n),r>=n.length)return Yt;const o=n.slice(r);let l=1;return()=>{if(!l)return;l=0;for(let e=0;e=0;--e)o.includes(t[e])&&t.splice(e,1)}},rn=(e,t,n)=>{const r=Ut(n,m);return r&&r.root?De(r.root,t):e},on=(e,t,n="dmSet")=>{if(at(e)){for(const t in e)ft(e,t)&&on(t,e[t],n);return e}if(e?.kind){if(e.kind!==h)return Et("dmSet target expected:",e,n),null}else{if("string"!=typeof e||!e)return Et("dmSet target expected:",e,n),null;if(e=je(tn(e,":"===e[0]?"si":"si:"))[i][0],e?.kind!==h)return Et("dmSet target expected:",e,n),null}return Ht(n,e,t),t};globalThis.dm=ze,globalThis.dmJsos=st,globalThis.wireNode=Qt,globalThis.dmScan=(e=document.body)=>{const n=[e],r=[];en(e);for(let e=0;e"function"!=typeof a?(Et("dmSub function expected:",l),Yt):nn(o,(e,t)=>{const n=je(l),r=n[u],o=n[s];if(!r.length||n[i].length||n[c].length)return Et("dmSub triggers/mods only:",l);let f=!1;for(const n of r){const r=Ze(n,o),s=(t,n,r,o,l)=>a(o,l,r,t,e);if(n.isSi){const o=_t(e,n,r,s,t);0!=n.isImmediate&&$t(o)}else{const o=n.isEv?et(e,l,n,r,Se,we,!1):null;if(n.isEv&&!o)return;if(null==(f=tt(e,n,r,s,t,f,o)))return}}}),globalThis.dmSel=Wt,globalThis.dmSelAll=Vt;const ln=(t,n,r)=>{const f=n.slice(7),d=e(f,a,0),p=he[d>=0?f.slice(0,d):f];if(!p)return Et("dmAct bad method:",n);const g=je(n),y=g[i],v=g[u],b=g[c],E=g[s],S=r?$e(r,n):null;if(r&&!S)return;const w=Ut(y,h);let x=null,A=!1,T=!1,I=!1,R=!1,B=!1,J=!1,H=!1,X=!1,re=!1,oe=!1,le=null,se=null,ie=!1,ue=!1,ce=!1,ae=P,fe=null,de=null;const me=[],pe=[],ge=[];for(const e of E){const t=e.root;"json"===t?A=!0:"text"===t?T=!0:"html"===t?I=!0:"form"===t?R=!0:"sse"===t?J=B=!0:"noCache"===t?J=!0:"brotli"===t||"br"===t?H=!0:"gzip"===t?X=!0:"deflate"===t?re=!0:"compress"===t?oe=!0:"hs"!==t||le?"hsNoKebab"===t?ie=!0:"auth"!==t||se?t===P||t===M||t===L||t===$||t===z||t===D||t===W||t===V?(ae=t,t!==M&&(fe=e)):t!==j||x?"retry"!==t||de?"url"===t?me.push(e):"body"===t?pe.push(e):"header"===t?ge.push(e):"syncAll"===t?ue=ce=!0:ue||"sendAll"!==t?ce||"patchAll"!==t||(ce=!0):ue=!0:de=e:x=e:se=e:le=e}w&&w.mods&&(ae=It(w.mods));const ye=(e=>{const t=((e,t)=>{if(!e)return null;const n=e.path;return"string"==typeof n?Te(h,null,n||t,null):n?.isSi?n:Te(h,null,t,null)})(e,j);if(!t)return null;let n=Re.get(t.root);n&&"object"==typeof n||Re.set(t.root,n=G());let r=n;const o=t.path;if(o&&o.length)for(let e=0;e{let i=e?Z:r?Y:t?ee:K;if(n&&(i=ht(i,Q)),i=o?ht(i,ne):l?ht(i,te):i,!s)return i;const u=i===K?G():dt(i);return u["accept-encoding"]=s,Object.freeze(u)})(A,T,I,R,B,J,Se),xe="GET"===p||"DELETE"===p;let Ae=null;for(const e of b){const t=e.path;e.key=(t?t.at(-1):e.root)||"value",e.isEv&&e.root&&(e.taEl=De(e.root,n));for(let t=0;tye&&Ht(n,ye[e],t),Ne=b.length>0,ke=Ie.length>0,Pe=async()=>{const e=S?S(ze,t,null,null,null):"";if(!e)return Et("dmAct empty URL:",n);Oe(C,!0),Oe(O,!1),Oe(N,null),Oe(k,null);try{const r=G(),s=G(),i=xe?r:s;if(ue)for(const[e,t]of Re.entries())s[e]=t;if(Ne)for(const e of b){const n=e.isEv?qe(e.taEl||t,e.path):ot(e);if(e.spread){if(n&&"object"==typeof n)for(const e in n)ft(n,e)?i[e]=n[e]:i.value=n}else i[e.key]=n}if(ke)for(const[e,t,n,o]of Ie)(e?s:r)[t]=o?ot(o):Re.get(n);let u=e,c=u.includes("?");for(const e in r)u+=(c?"&":"?")+encodeURIComponent(e)+"="+encodeURIComponent(""+(r[e]??"")),c=!0;let a=K,f=1;if(ve){const e=lt(ve);if(at(e)){a=G(),f=0;for(const t in e)ft(e,t)&&(a[ie?t:l(t)]=""+e[t])}}if(we!==K)if(a===K)a=we;else for(const e in we)ft(we,e)&&(a[e]=we[e]);if(null!=be){const e=lt(be);null!=e&&(f&&(a=dt(a),f=0),a.authorization=""+e)}for(const[e,t,n]of Ce){f&&(a=dt(a),f=0);const r=n?ot(n):Re.get(t);a[e]=null!=r?""+r:""}let d=0,g=null,v=null;for(const e in s)ft(s,e)&&(d||(g=e),d++);if(d){const e=1===d?s[g]:s;if(R&&(at(e)||Array.isArray(e))){const t=new URLSearchParams;if(Array.isArray(e))for(let n=0;nE.abort():null,Oe(U,Ae);const S={method:p,headers:a};null!=v&&(S.body=v),E&&(S.signal=E.signal);const x=await window.fetch(u,S),T=x.headers?.get("content-type")||"",j=T.includes("text/event-stream");let P;if(j)x.body&&"function"==typeof x.body.getReader?P=await Cn(x.body,n,ye):(Oe(F,!0),P=In(await x.text(),n),Oe(F,!1),Oe(_,!0));else if(I&&T.includes("text/html")){P=await x.text();const e=fe?.root||q,n=fe&&fe.path,r=n?"":Ut(y,m)?.root??"";let o="";if(n){const e=lt(n);"string"==typeof e&&e&&(o="#.[*:".includes(e[0])?e:"#"+e)}else o=e===z||e===D?t.id?"#"+t.id:"":e!==L&&e!==$||!r?"":"#"+r;wn({[En]:P,selector:o,mode:e})}else{if(P=(e=>{const t=(e||"").toLowerCase();if(t.indexOf("application/json")>=0)return!0;const n=t.indexOf("+json");if(n<0)return!1;const r=n+5;if(r>=t.length)return!0;const o=t[r];return";"===o||" "===o||"\t"===o})(T)?await x.json():await x.text(),w){const e=ot(w);Ht(n,w,Tt(e,P,ae))}if(ce&&at(P))for(const e in P)if(ft(P,e)){const t=o(e);Re.has(t)&&Ht(n,Te(h,null,t,null),Tt(Re.get(t),P[e],ae))}}Oe(C,!1),Oe(O,!0),Oe(N,null),Oe(k,Number.isFinite(x.status)?x.status:null),Oe(U,null),Ae=null,!(Ee>0&&j)||E&&E.signal.aborted||setTimeout(Pe,Ee)}catch(e){Ae=null;const t=e&&"AbortError"===e.name;Oe(U,null),Oe(F,!1),Oe(C,!1),Oe(O,!0),t||(Oe(N,e&&e.message?e.message:""+e),Oe(k,Number.isFinite(e&&e.status)?e.status:null),Et("dmAct fail:",e),Ee>0&&setTimeout(Pe,Ee))}};if(!v.length)return void Pe();const Me=jt(Kt,t);let Le=!1;for(const e of v){if(!e.isSi&&!e.isEv&&!e.isSp)return Et("dmAct bad trigger:",e.kind,n);if(e.isSp){if(!e.sp?.act)return Et("dmAct unsupported SP",e.root,"in",n);Le||(Le=!0,Pe());continue}const r=Ze(e,E);if(e.isSi){_t(t,e,r,Pe,Me),!Le&&e.isImmediate&&(Le=!0,Pe());continue}const o=e.root?De(e.root,n):t;if(!o)return Et("dmAct el not found:",e,"in:",n);const l=e.path?.[0]??Ve(o);if(!l)return Et("dmAct event not found:",e,"in:",n);const s=_t(t,e,r,Pe,Me,o,l,null,null,o);!Le&&e.isImmediate&&(Le=!0,Lt(s,null,qe(o,null),t,e))}},sn=new WeakSet,un=new WeakSet,cn=(e,n)=>{if(!n||n.indexOf("-")<0)return Et("dmWc needs custom-element name:",n);if(customElements.get(n)||sn.has(e))return;sn.add(e);const r=(e.getAttribute(me+"wc-props")||"").match(/[^,\s]+/g)||t,o=class extends HTMLElement{connectedCallback(){if(!un.has(this)){un.add(this),!this.firstElementChild&&e.content&&(this.appendChild(e.content.cloneNode(!0)),St(this));for(const e of r){let t=this["$"+e];ft(this,e)&&(t=this[e],delete this[e]),void 0!==t&&(this[e]=t)}}}};for(const e of r)Object.defineProperty(o.prototype,e,{get(){return this["$"+e]},set(t){this["$"+e]=t,this.dispatchEvent(new CustomEvent(e,{detail:t})),this.firstElementChild&&this.firstElementChild.dispatchEvent(new CustomEvent(e,{detail:t}))}});customElements.define(n,o)};globalThis.dmAct=(e,t,n)=>nn(e,e=>ln(e,tn(t,""),n)),Zt.si=(e,t,n)=>{const r=je(t),l=r[i];(r[s].length||r[u].length||r[c].length)&&bt("targets only:",t);let a=$e(n,t);if(!a)return;let f=n?a(ze,e,null):null;if(l.length)for(const e of l)e.kind==h?(e.mods.length&&bt("mods ignored:",e.mods,t),Re.set(e.root,f)):Et("signal targets only:",e,t);else{if(!f||"object"!=typeof f)return Et("object value expected:",t,n);for(const e in f)Re.set(o(e),f[e])}},Zt.ex=(e,t,n)=>{const r=je(t),o=r[i],l=r[u],a=r[s];r[c].length&&bt("targets/triggers/mods only:",t);const f=null!=n&&""+n;let d=f?$e(n,t):(e,t,n,r)=>r;if(f&&!d)return;const h=e?jt(Kt,e):null;if(!o.length&&l.length){const n=[],r=[],o=[];for(const s of l){const l=Ze(s,a);if(!(16&l.f)){n.push({tr:s,mod:l}),s.isSi&&o.push([s,It(s.mods)]);continue}if(!s.isEv)return Et(ve,t);const i=et(e,t,s,l,be,Ee);if(!i)return;r.push({tr:s,mod:l,w:It(s.mods),taEl:i.taEl,readEl:i.readEl,ev:i.ev,prPath:i.prPath,readPath:i.readPath,tar:i.tar})}if(r.length&&n.length){let l=!1;const s=(n,o,l,s)=>{const i=d(n,e,o,l,s);for(const n of r)Be(e,t,n.tar,Tt(qe(n.taEl,n.prPath),i,n.w))};for(const r of n){const n=r.tr,o=r.mod;if(n.isSi){const t=_t(e,n,o,(e,t,n,r,o)=>s(e,n,r,o),h);l||0==n.isImmediate||(l=!0,$t(t))}else{if(!n.isEv&&!n.isSp)return Et("bad trigger kind",n.kind,"in",t);{const r=n.isEv?et(e,t,n,o,be,Ee):null;if(n.isEv&&!r)return;if(null==(l=tt(e,n,o,(e,t,n,r,o)=>s(e,n,r,o),h,l,r)))return}}}if(o.length)for(const n of r){const r=_t(e,n.tr,n.mod,(n,r,l,s,i)=>{const u=d(n,e,l,s,i);for(const e of o)Ht(t,e[0],Tt(rt(e[0]),u,e[1]))},h,n.taEl,n.ev,n.prPath,n.readPath,n.readEl);0!=n.tr.isImmediate&&Lt(r,null,qt(n.readEl,n.mod,n.readPath),e,n.tr)}return}}if(o.length){const e=d;for(const e of o)e._m=It(e.mods),e._j=!(!e.mods||!e.mods.some(e=>e.root===I)),e.isSi||(e._el=e.isSp?e.root===re?window:e.root===oe?document:e.root===le?window.history:null:e.root?De(e.root,t):null);d=(n,r,l,s,i)=>{const u=e(n,r,l,s,i);try{for(const e of o){const n=e._j?st(u):u,o=Tt(e.isSi?rt(e):qe(e._el||r,e.path),n,e._m);e.isSi?Ht(t,e,o):Be(r,t,e,o)}}catch(e){Et("setting target in",t,"ended with ex:",e)}}}if(!l.length)return void(f&&d(ze,e,null,null,null));let m=!1;for(const n of l){const r=Ze(n,a);if(n.isSi){const t=_t(e,n,r,d,h);m||0==n.isImmediate||(m=!0,$t(t));continue}if(!n.isEv&&!n.isSp)return Et("bad trigger kind",n.kind,"in",t);const o=n.isEv&&et(e,t,n,r,Se,we,!1);if(n.isEv&&!o)return;if(null==(m=tt(e,n,r,d,h,m,o)))return}},Zt.it=(e,t)=>{const n=je(t),r=n[u],o=n[c],l=n[s];if(!r.length)return Et("dmIt needs signal trigger:",t);const i=r[0];if(!i.isSi)return Et("dmIt trigger must be signal:",t);const a=Ze(i,l);let f=null;if(o.length&&o[0].isEv&&o[0].root&&(f=De(o[0].root,t)),f||(f=e.querySelector("template")),f&&f.parentNode===e&&f.parentNode.removeChild(f),!f)return Et("dmIt tpl not found:",t);const d=f.content&&f.content.firstElementChild;if(!d)return Et("dmIt tpl root not found:",t);let h=xe.get(e);h||xe.set(e,h={nodes:[],count:0});const m=((e,t)=>{let n=e;if(t)for(let e=0;e{let n="dm."+e;if(t)for(let e=0;ext(e,i,h,d,m,p),jt(Kt,e)),(i.isImmediate??1)&&xt(e,i,h,d,m,p)},Zt.wc=(e,t,n)=>"TEMPLATE"===e.tagName?cn(e,n&&n.trim()):Et("dmWc template-only, use data-m-ex for host props:",t),Zt.cl=(e,t,n)=>{const r=je(t),o=r[c],l=r[i],a=r[u],f=r[s];if(!o.length)return Et("dmCl needs class names via +:",t);if(!a.length)return Et("dmCl needs trigger:",t);const d=rn(e,t,l);if(!d)return Et("dmCl target not found:",t);const h=n?$e(n,t):null;if(n&&!h)return;const m=jt(Kt,e);for(const n of a){const r=Ze(n,f);if(n.isSi){const t=_t(e,n,r,(e,t,n,r,l)=>He(o,d,h?h(e,t,n,r,l):r),m);0!=n.isImmediate&&$t(t)}else{const l=n.isEv?et(e,t,n,r,Se,we,!1):null;if(n.isEv&&!l)return;if(null==tt(e,n,r,(t,r,l,s,i)=>He(o,d,!h||h(t,e,n,s,i)),m,!1,l))return}}},Zt.sh=(e,t,n)=>{const r=je(t),o=r[i],l=r[u],c=r[s];if(!l.length)return Et("dmSh needs trigger:",t);const a=rn(e,t,o);if(!a)return Et("dmSh target not found:",t);const f=a.style&&a.style.display||"",d=Je(a),h=f||("none"!==d&&d?d:"block"),m=n?$e(n,t):null;if(n&&!m)return;const p=jt(Kt,e);for(const n of l){const r=Ze(n,c);if(n.isSi){const t=_t(e,n,r,(e,t,n,r,o)=>Xe(a,f,h,m?m(e,t,n,r,o):r),p);0!=n.isImmediate&&$t(t)}else{const o=n.isEv?et(e,t,n,r,Se,we,!1):null;if(n.isEv&&!o)return;if(null==tt(e,n,r,(t,r,o,l,s)=>Xe(a,f,h,!m||m(t,e,n,l,s)),p,!1,o))return}}},Zt.dbg=e=>{e&&(Nt.add(e),Bt())},Zt.no=()=>{},Zt.get=Zt.post=Zt.put=Zt.patch=Zt.delete=ln;const an=(e,t)=>e.nodeType===t.nodeType&&(1!==e.nodeType||(e.id&&t.id?e.id===t.id:e.tagName===t.tagName)),fn=(e,t)=>e.nodeType===t.nodeType&&(1!==e.nodeType||(e.id||t.id?e.id===t.id:e.tagName===t.tagName)),dn=document.createElement("template"),hn=new Map,mn=(e,n=e&&(e=>{if(!e||"#"!==e[0])return null;const t=hn.get(e);if(void 0!==t)return t;for(let t=1;t+~:.[],|".includes(e[t]))return null;const n=e.length>1?e.slice(1):null;return hn.set(e,n),n})(e),r=n&&document.getElementById(n))=>e?n?r?[r]:t:document.querySelectorAll(e):t,pn=(e,t)=>{let n=e.firstChild,r=t.firstChild;for(;n&&r&&fn(n,r);){const e=n.nextSibling;vn(n,r),n=e,r=r.nextSibling}if(!n){for(;r;r=r.nextSibling)e.appendChild(r.cloneNode(!0));return}if(!r){for(;n;){const t=n.nextSibling;e.removeChild(n),n=t}return}let o=null,l=0;for(let e=n;e;e=e.nextSibling)1===e.nodeType&&e.id&&((o??=G())[e.id]=e,l=1);for(;r;r=r.nextSibling){let t=null,s=1===r.nodeType?r.id:"";if(s&&o&&(t=o[s]))delete o[s];else{for(;l&&n&&1===n.nodeType&&n.id&&o[n.id];)n=n.nextSibling;n&&an(n,r)&&(t=n)}t?(t!==n?e.insertBefore(t,n||null):n=n.nextSibling,vn(t,r)):e.insertBefore(r.cloneNode(!0),n||null)}for(;n;){const t=n.nextSibling;e.removeChild(n),n=t}if(o)for(const t in o){const n=o[t];n.parentNode===e&&e.removeChild(n)}};let gn=null;const yn=e=>e&&(gn=null),vn=(e,t)=>{const n=null===gn;if(n&&(gn=document.activeElement),3===e.nodeType&&3===t.nodeType)return e.nodeValue!==t.nodeValue&&(e.nodeValue=t.nodeValue),yn(n);if(1!==e.nodeType||1!==t.nodeType||vt(e)||vt(t))return yn(n);if(e.tagName!==t.tagName)return e.parentNode&&e.parentNode.replaceChild(t.cloneNode(!0),e),yn(n);const r=e.firstChild,o=t.firstChild,l=r&&o&&!r.nextSibling&&!o.nextSibling&&3===r.nodeType&&3===o.nodeType,s=((e,t)=>{const n=e.attributes,r=t.attributes,o=r.length;if(n.length!==o)return!1;for(let e=0;e{const n=t.attributes,r=e.attributes,o=n.length,l=r.length;if(l===o){let e=!0,t=!1;for(let l=0;l=0;n--)t.hasAttribute(r[n].name)||e.removeAttribute(r[n].name)}else for(let t=l-1;t>=0;t--)e.removeAttribute(r[t].name)})(e,t),l?r.nodeValue!==o.nodeValue&&(r.nodeValue=o.nodeValue):(r||o)&&pn(e,t),(h||m)&&(e.scrollTop!==h&&(e.scrollTop=h),e.scrollLeft!==m&&(e.scrollLeft=m)),i&&u>=0)try{e.setSelectionRange(u,c,a)}catch(e){}else i&&null!==f&&(e.value=f,e.value!==f&&d>=0&&d{if(e&&t)if(n===P)e.replaceWith(r?t:t.cloneNode(!0));else if(n===W){const n=e.cloneNode(!1);for(let e=t.firstChild;e;e=e.nextSibling)n.appendChild(e.cloneNode(!0));pn(e,n)}else vn(e,t)},wn=e=>{const n=(e.mode||q).toLowerCase(),r=e.selector?""+e.selector:"",o=e.namespace?""+e.namespace:"html",l=e[En]||"";if(n===P&&"html"===o&&l){const e=r&&mn(r),t=!r&&/^\s*<[^>]*\sid\s*=\s*(?:"([^"]+)"|'([^']+)')/i.exec(l),n=r?1===e.length&&e[0]:document.getElementById(t&&(t[1]||t[2]||""));if(n)return void(n.outerHTML=""+l)}const s=((e,n)=>{if(!e)return t;const r=(n||"html").toLowerCase();if("html"===r){dn.innerHTML=e;const n=dn.content.firstElementChild;if(!n)return t;if(!n.nextElementSibling)return[n];const r=[n];for(let e=n.nextElementSibling;e;e=e.nextElementSibling)r.push(e);return r}const o="svg"===r?`${e}`:`${e}`,l=(new DOMParser).parseFromString(o,"svg"===r?"image/svg+xml":"application/xml").documentElement;return l?Array.from(l.children):[]})(l,o);if(n!==V)if(n!==L&&n!==$&&n!==z&&n!==D){if(r){if(!s.length)return;const e=mn(r);if(1===e.length&&1===s.length)return void Sn(e[0],s[0],n,!0);const t=s[0];for(let r=0;r{if(null===t)return bn;if(!at(t))return t;const n=at(e)?dt(e):G();for(const e in t)if(ft(t,e)){const r=xn(n[e],t[e]);r===bn?delete n[e]:n[e]=r}return n},An=(e,t,n)=>{const r=t[1],o=t[0];t[2]&&r&&("dm-elements"===o?(wn(r),e.push({event:o,args:r})):"dm-signals"===o&&(((e,t)=>{const n=t.dmSignals;if(!n)return;let r=null;try{r=JSON.parse(n)}catch(t){return Et("patch sigs in",e,"expect JSON but found invalid format")}if(!at(r))return;const o="true"===(t.onlyIfMissing||"").toLowerCase();for(const t in r)if(ft(r,t)){if(o&&Re.has(t))continue;const n=xn(Re.get(t),r[t]),l=Te(h,null,t,null);n!==bn?Ht(e,l,n):Re.has(t)&&(Ht(e,l,void 0),Re.delete(t),Bt())}})(n,r),e.push({event:o,args:r}))),t[0]="message",t[1]=null,t[2]=!1},Tn=(e,t,n,r)=>{const o="\r"===e[e.length-1]?e.slice(0,-1):e;if(!o)return An(n,t,r);if(":"===o[0])return;const l=o.indexOf(":"),s=l<0?o:o.slice(0,l);let i=l<0?"":o.slice(l+1);if(" "===i[0]&&(i=i.slice(1)),"event"===s)t[0]=i||"message";else if("data"===s){const e=i.indexOf(" ");if(e<0)return;const n=i.slice(0,e),r=i.slice(e+1),o=t[1]||(t[1]=G());t[2]=!0,o[n]?o[n]+="\n"+r:o[n]=r}},In=(e,n="dmax-sse")=>{if(!e)return t;const r=[],o=""+e,l=["message",null,!1];let s,i=0;for(;(s=o.indexOf("\n",i))>=0;)Tn(o.slice(i,s),l,r,n),i=s+1;return i{if(!e||"function"!=typeof e.getReader)return t;const o=(e,t)=>r&&Ht(n,r[e],t),l=[],s=e.getReader(),i=new TextDecoder,u=["message",null,!1];let c="",a=!1;try{for(;;){const{done:e,value:t}=await s.read();if(e)break;let r;for(a||(a=!0,o(F,!0),o(_,!1)),c+=i.decode(t,{stream:!0});(r=c.indexOf("\n"))>=0;)Tn(c.slice(0,r),u,l,n),c=c.slice(r+1)}const e=i.decode();e&&(c+=e),c&&Tn(c,u,l,n),An(l,u,n)}catch(e){return o(F,!1),o(N,e.message||""+e),Et("SSE stream error:",e),l}return o(F,!1),o(_,!0),l},On=e=>{if(!e||1!==e.nodeType&&11!==e.nodeType)return;const n=[e];for(;n.length;){const e=n.pop(),r=Kt.get(e);if(r){for(const e of r)Pt(e);Kt.delete(e)}const o=e.shadowRoot;o&&n.push(o);const l=e.children||t;for(let e=0;e{for(const t of e)for(const e of t.removedNodes)On(e)}),kn=new WeakSet;en=e=>{!e||kn.has(e)||1!==e.nodeType&&11!==e.nodeType||(kn.add(e),Nn.observe(1===e.nodeType?e:e===document?document.body:e,{childList:!0,subtree:!0}))},en(document.body); diff --git a/dist/dmax.min.js.br b/dist/dmax.min.js.br index 60237ba..2d18c89 100644 Binary files a/dist/dmax.min.js.br and b/dist/dmax.min.js.br differ diff --git a/dist/dmax.min.js.gz b/dist/dmax.min.js.gz index 96dd36d..8cc560b 100644 Binary files a/dist/dmax.min.js.gz and b/dist/dmax.min.js.gz differ diff --git a/dmax.js b/dmax.js index 798f1f9..09cd408 100644 --- a/dmax.js +++ b/dmax.js @@ -30,7 +30,6 @@ const MOD = '^', TARG = ':', TRIG = '@', ADD = '+' const ALL = [MOD, TARG, TRIG, ADD] - const MODS = [MOD] const DOT = '.', ID = '#', NOT = '!', BRACKET_OPEN = '[', BRACKET_CLOSE = ']' const NAME_DELIMS = [DOT, BRACKET_OPEN] @@ -77,15 +76,15 @@ }) const ACT_METHODS = Object.freeze({ get: 'GET', post: 'POST', put: 'PUT', patch: 'PATCH', delete: 'DELETE' }), DM_KEY = 'data-m-' const DM_NO = DM_KEY + 'no', DM_NO_SCAN = DM_NO + '^scan', DM_NO_MORPH = DM_NO + '^morph' - const E_RW_REQ = `dmEx ${MOD}${M_RW} requires an element/property trigger in:` - const E_RW_EL = `dmEx ${MOD}${M_RW} source element is not found in trigger:` - const E_RW_EV = `dmEx ${MOD}${M_RW} event is not found in trigger:` - const E_TRIG_EL = 'Element is not found in trigger:', E_TRIG_EV = 'Event is not found in trigger:', E_FORM_EL = 'Form element is not found for trigger:' + const E_RW_REQ = `dmEx ${MOD}${M_RW} requires element/property trigger:` + const E_RW_EL = `dmEx ${MOD}${M_RW} element not found:` + const E_RW_EV = `dmEx ${MOD}${M_RW} event not found:` + const E_TRIG_EL = 'element not found:', E_TRIG_EV = 'event not found:', E_FORM_EL = 'form element not found:' const IT_STATES = new WeakMap(), IT_ATTRS = new WeakMap() const isSp = (n) => { if (n.startsWith(SP)) for (const s of SPS) if (n.startsWith(s, 1)) return true; return false } const mkIt = (kind, not, root, path, mods = NIL) => ({ kind, not, root, path, mods, sp: kind === SP ? SP_DEFS[root] || null : null, isSi: kind === SI, isEv: kind === EP, isSp: kind === SP, isImmediate: null }) const mkMod = (not, root, path) => ({ kind: MOD, not, root, path, isImmediate: root === M_IMMEDIATE ? true : root === M_NOT_IMMEDIATE ? false : null }) - const DEFAULT_PR_TA = Object.freeze(mkIt(EP, null, '', null)), RE_DIGITS = /^\d+$/ + const RE_DIGITS = /^\d+$/ const parseRef = (dKey, n, pos = 0) => { if (!n) return null let p = pos, l = n.length @@ -281,7 +280,7 @@ const VAL_CHANGE_DEPTH_MAX = 32 const valChangedDeep = (before, after, depth = 0) => { - if (depth >= VAL_CHANGE_DEPTH_MAX) { console.warn('[dmax] Warning: too deep to compare for signal value change, consider it changed, stopped at:', VAL_CHANGE_DEPTH_MAX); return true } + if (depth >= VAL_CHANGE_DEPTH_MAX) { console.warn('[dmax] deep compare limit:', VAL_CHANGE_DEPTH_MAX); return true } const b = before, a = after if (Array.isArray(b)) { // means b is also an array if (!Array.isArray(a) || b.length != a.length) return true @@ -302,7 +301,7 @@ let obj = tar.isSp ? tar.root === SP_WIN ? window : tar.root === SP_DOC ? document : tar.root === SP_HISTORY ? window.history : null : tar.root ? getElById(tar.root, dKey) : el const path = tar.path; let prop = !path ? getDefaultPr(obj) : null if (path && path.length) ([obj] = getPrValAndDepth(obj, path, path.length - 1), prop = path.at(-1)) - if (!obj || !prop) return logErr('Error setting non existing property for:', tar, 'in', dKey) + if (!obj || !prop) return logErr('setting non-existing prop:', tar, 'in', dKey) try { if (typeof obj[prop] === 'function') return Array.isArray(val) ? obj[prop](...val) : obj[prop](val) if (prop === 'style' && isPlainObj(val) && obj[prop]) for (const k in val) { @@ -313,7 +312,7 @@ const cssVar = prop[0] === '-' ? prop : '--' + camelToKebab(prop) if (obj.getPropertyValue(cssVar) !== '' + val) obj.setProperty(cssVar, val) } else if (valChangedDeep(obj[prop], val)) obj[prop] = val - } catch (e) { logErr('Error: Failed to set property:', e.message, '>>>', tar, 'on', el) } + } catch (e) { logErr('Failed to set property:', e.message, '>>>', tar, 'on', el) } return obj[prop] } const getComputedDisplay = (el) => (typeof window !== 'undefined' && window.getComputedStyle) ? window.getComputedStyle(el).display : '' @@ -404,15 +403,15 @@ } const getTrPrTa = (el, dKey, tr, mod, missElMsg, missEvMsg, usePrPath = true) => { const taEl = tr.root ? getElById(tr.root, dKey) : el - if (!taEl) return logErr('Error:', missElMsg, tr, 'in:', dKey), null + if (!taEl) return logErr(missElMsg, tr, 'in:', dKey), null let ev = tr.path ? tr.path[0] : null, prPath = null if (ev && isDefaultPrName(taEl, ev)) prPath = tr.path, ev = getDefaultEv(taEl) const readEl = (mod.s === MV_PR || mod.s === MV_ATTRS) && mod.r ? getElById(mod.r, dKey) : taEl const readPath = mod.s === MV_PR || mod.s === MV_EV ? mod.v.length ? mod.v : prPath : mod.s === MV_ATTRS || mod.s === MV_SEL || mod.s === MV_SEL_ALL ? mod.v : prPath if (usePrPath && mod.s === MV_PR && !mod.r && mod.v.length) prPath = mod.v ev = ev ?? getDefaultEv(taEl) - if (!ev) return logErr('Error:', missEvMsg, tr, 'in:', dKey), null - return readEl ? { taEl, readEl, ev, prPath, readPath, tar: mkIt(EP, null, tr.root, prPath, NIL) } : logErr('Error:', missElMsg, tr, 'in:', dKey) + if (!ev) return logErr(missEvMsg, tr, 'in:', dKey), null + return readEl ? { taEl, readEl, ev, prPath, readPath, tar: mkIt(EP, null, tr.root, prPath, NIL) } : logErr(missElMsg, tr, 'in:', dKey) } const addNonSiTrSub = (el, tr, mod, fn, elSubs, ran, prTa = null) => { const sp = tr.sp, isSp = !!sp @@ -447,13 +446,6 @@ } const dmJsos = (v, sp = 2) => typeof v === 'string' ? v : JSON.stringify(v, null, +(resolveMPathVal(sp) ?? 2) || 0) - const resolveHtmlSelector = (mPath) => { - const v = resolveMPathVal(mPath) - if (typeof v === 'string' && v) { - const c = v[0]; return SEL_LEADS.includes(c) ? v : '#' + v - } - return '' - } const mkOrStatSi = (mod, fallbackRoot) => { if (!mod) return null const p = mod.path @@ -461,23 +453,17 @@ } const mkStatTar = (root, path, key) => ({ root, path: path ? path.concat(key) : [key] }) const STAT_KEYS_F = [M_BUSY, M_COMPLETE, M_SSE_OPEN, M_SSE_CLOSE], STAT_KEYS_N = [M_ERR, M_CODE, M_ABORT] - const defStatSi = (stat) => { + const mkActStats = (mod) => { + const stat = mkOrStatSi(mod, M_STAT) if (!stat) return null - let cur = _dm.get(stat.root) - if (!cur || typeof cur !== 'object') _dm.set(stat.root, cur = noProto()) - let parent = cur - const path = stat.path + let cur = _dm.get(stat.root); if (!cur || typeof cur !== 'object') _dm.set(stat.root, cur = noProto()) + let parent = cur; const path = stat.path if (path && path.length) for (let i = 0; i < path.length; ++i) parent = parent[path[i]] && typeof parent[path[i]] === 'object' ? parent[path[i]] : (parent[path[i]] = noProto()) for (const k of STAT_KEYS_F) if (!hasOwn(parent, k)) parent[k] = false for (const k of STAT_KEYS_N) if (!hasOwn(parent, k)) parent[k] = null - return stat - } - const mkActStats = (mod) => { - const stat = defStatSi(mkOrStatSi(mod, M_STAT)) - if (!stat) return null - const { root, path } = stat, out = noProto() - for (const k of STAT_KEYS_F) out[k] = mkStatTar(root, path, k) - for (const k of STAT_KEYS_N) out[k] = mkStatTar(root, path, k) + const { root, path: sp } = stat, out = noProto() + for (const k of STAT_KEYS_F) out[k] = mkStatTar(root, sp, k) + for (const k of STAT_KEYS_N) out[k] = mkStatTar(root, sp, k) return out } @@ -567,7 +553,7 @@ } const noScan = (el) => el && el.hasAttribute && (el.hasAttribute(DM_NO) || el.hasAttribute(DM_NO_SCAN)) - const noMorph = (el) => el && el.hasAttribute && (el.hasAttribute(DM_NO) || el.hasAttribute(DM_NO_MORPH)) + const noMorph = (el) => el.hasAttribute(DM_NO) || el.hasAttribute(DM_NO_MORPH) const warn = (...a) => console.warn('[dmax]', ...a), logErr = (...a) => console.error('[dmax]', ...a) const wireItClone = (node) => { const stack = [node] @@ -595,25 +581,21 @@ if (!expected(Array.isArray(val), 'dmIt expected array value from:', tr, 'on:', el)) return const newLen = val.length, oldLen = itState.count || 0 if (newLen < oldLen) { - for (let i = 0; i < oldLen - newLen; i++) { - const node = itState.nodes.pop() - if (node && node.parentNode) node.parentNode.removeChild(node) - } + for (let i = 0; i < oldLen - newLen; i++) { const node = itState.nodes.pop(); if (node && node.parentNode) node.parentNode.removeChild(node) } itState.count = newLen } if (newLen > oldLen) { - const frag = document.createDocumentFragment() - for (let idx = oldLen; idx < newLen; idx++) { - try { - const node = tplFirst.cloneNode(true) - const idxText = '' + idx - rewriteItBindings(node, itemRefBase + '.' + idxText, itemExprBase + '[' + idxText + ']', idxText) - frag.appendChild(node) - itState.nodes.push(node) - } catch { } + const count = newLen - oldLen + if (count === 1) { + const node = tplFirst.cloneNode(true), idxText = '' + oldLen + rewriteItBindings(node, itemRefBase + '.' + idxText, itemExprBase + '[' + idxText + ']', idxText) + el.appendChild(node), itState.nodes.push(node) + } else { + const frag = document.createDocumentFragment() + for (let idx = oldLen; idx < newLen; idx++) { try { const node = tplFirst.cloneNode(true), idxText = '' + idx; rewriteItBindings(node, itemRefBase + '.' + idxText, itemExprBase + '[' + idxText + ']', idxText); frag.appendChild(node); itState.nodes.push(node) } catch { } } + el.appendChild(frag) } - el.appendChild(frag) - for (let i = itState.nodes.length - (newLen - oldLen); i < itState.nodes.length; ++i) wireItClone(itState.nodes[i]) + for (let i = itState.nodes.length - count; i < itState.nodes.length; ++i) wireItClone(itState.nodes[i]) itState.count = newLen } } @@ -637,21 +619,6 @@ } const getWriteMode = (mods) => { for (const m of mods || NIL) if (m.root === M_REPLACE || m.root === M_MERGE || m.root === M_APPEND || m.root === M_PREPEND || m.root === M_INC || m.root === M_DEC) return m.root; return M_REPLACE } - const patchMatchingSis = (dKey, payload, resultMode) => { - if (!isPlainObj(payload)) return - for (const key in payload) if (hasOwn(payload, key)) { - const root = kebabToCamel(key) - if (!_dm.has(root)) continue - setSiAndNotifySubsNDeep(dKey, mkIt(SI, null, root, null), combineActResult(_dm.get(root), payload[key], resultMode)) - } - } - - const applyActPayload = (dKey, resultTa, payload, resultMode) => { - if (!resultTa) return - const prev = getSiValOrIt(resultTa) - setSiAndNotifySubsNDeep(dKey, resultTa, combineActResult(prev, payload, resultMode)) - } - const permitVal = (m, val, n = m.root, v = resolveMPathVal(m.path)) => n === M_AND ? !!v != !!m.not : n == M_EQ ? val == v : n == M_NE ? val != v : n == M_GT ? +val > +v : n == M_LT ? +val < +v : n == M_GE ? +val >= +v : +val <= +v const modsPermitVal = (mods, val) => !mods.push ? permitVal(mods, val) : !mods.some((m) => !permitVal(m, val)) @@ -723,7 +690,7 @@ return sub.fn } if (sp.io) { - if (typeof IntersectionObserver === 'undefined') { warn('IntersectionObserver missing, skip _viewed:', el); return null } + if (typeof IntersectionObserver === 'undefined') { warn('no IntersectionObserver:', el); return null } const sub = { el, trig: tr, fn: null, siChangeM: null, ev: null, clearId: null } sub.fn = applyTrMs(fn, tr, mod, sub) const observer = new IntersectionObserver((entries) => { @@ -739,7 +706,7 @@ if (sp.init) return applyTrMs(fn, tr, mod) const taEl = sp.ta === SP_TA_WIN ? window : sp.ta === SP_TA_DOC ? document : sp.ta === SP_TA_FORM ? (el && el.closest ? el.closest('form') : null) : null const ev = tr.path?.[0] || sp.ev || null, readPath = mod.s === MV_PR ? mod.v.length ? mod.v : null : mod.s === MV_ATTRS || mod.s === MV_SEL || mod.s === MV_SEL_ALL ? mod.v : null - if (sp.ta === SP_TA_FORM && !taEl) return logErr('Error:', E_FORM_EL, tr, 'on:', el), null + if (sp.ta === SP_TA_FORM && !taEl) return logErr(E_FORM_EL, tr, 'on:', el), null if (!expected(taEl && ev, 'Expected event target/name in addSpSub:', tr, 'on:', el)) return null const opts = mod.f & MF_PREVENT ? false : PASSIVE_LISTENER_OPTS const sub = { el, trig: tr, fn: null, siChangeM: null, ev: { taEl, evName: ev, opts }, clearId: null } @@ -860,16 +827,6 @@ try { return setSiAndNotifySubs(dKey, tar, val) } finally { syncDepth-- } } - /** - * @typedef {(dm?: any, el?: any, trig?: any, trigVal?: any, detail?: any) => void} TriggerHandler - */ - - /** - * @param {TriggerHandler} fn - * @param {{ kind: string, root?: string, path?: any, not?: any }} trig - * @param {{ el?: any, trig: any, fn?: any, siChangeM?: any, ev?: { taEl: EventTarget, evName: string, opts: any } | null, clearId?: any } | undefined} [removeSub] - * @returns {TriggerHandler} - */ const onRaf = (fn) => (typeof requestAnimationFrame === 'function' ? requestAnimationFrame : setTimeout)(fn, 16) const getEvVal = (detail, dd = detail && detail.detail) => dd === undefined ? detail : dd && typeof dd === 'object' ? dd.value ?? dd.ms ?? dd : dd const applyTrMs = (fn, tr, mod, removeSub) => { @@ -940,7 +897,7 @@ if (tr.isSi) writeSiTrs.push([tr, getWriteMode(tr.mods)]) continue } - if (!tr.isEv) return logErr('Error:', E_RW_REQ, dKey) + if (!tr.isEv) return logErr(E_RW_REQ, dKey) const prTa = getTrPrTa(el, dKey, tr, mod, E_RW_EL, E_RW_EV) if (!prTa) return writePrTrs.push({ tr, mod, w: getWriteMode(tr.mods), taEl: prTa.taEl, readEl: prTa.readEl, ev: prTa.ev, prPath: prTa.prPath, readPath: prTa.readPath, tar: prTa.tar }) } @@ -959,7 +916,7 @@ const prTa = tr.isEv ? getTrPrTa(el, dKey, tr, mod, E_RW_EL, E_RW_EV) : null if (tr.isEv && !prTa) return if ((ran = addNonSiTrSub(el, tr, mod, (dm, _el, syncTr, trigVal, detail) => syncPrTas(dm, syncTr, trigVal, detail), elSubs, ran, prTa)) == null) return - } else return logErr('Error: unsupported trigger kind', tr.kind, 'in', dKey) + } else return logErr('bad trigger kind', tr.kind, 'in', dKey) } if (writeSiTrs.length) { for (const prTr of writePrTrs) { @@ -976,19 +933,11 @@ } if (tars.length) { const rawFn = fn + for (const tar of tars) { tar._m = getWriteMode(tar.mods); tar._j = !!(tar.mods && tar.mods.some((m) => m.root === M_JSOS)); if (!tar.isSi) tar._el = tar.isSp ? tar.root === SP_WIN ? window : tar.root === SP_DOC ? document : tar.root === SP_HISTORY ? window.history : null : tar.root ? getElById(tar.root, dKey) : null } fn = (dm, el, trig, trigVal, detail) => { const exprVal = rawFn(dm, el, trig, trigVal, detail) - let failedTa = null - try { - for (const tar of tars) { - failedTa = tar - const mode = getWriteMode(tar.mods) - const outVal = tar.mods && tar.mods.some((m) => m.root === M_JSOS) ? dmJsos(exprVal) : exprVal - const nextVal = tar.isSi ? combineActResult(getSiVal(tar), outVal, mode) : combineActResult(getElPrVal(tar.isSp ? tar.root === SP_WIN ? window : tar.root === SP_DOC ? document : tar.root === SP_HISTORY ? window.history : null : tar.root ? getElById(tar.root, dKey) : el, tar.path), outVal, mode) - if (tar.isSi) setSiAndNotifySubsNDeep(dKey, tar, nextVal) - else setPr(el, dKey, tar, nextVal) - } - } catch (e) { logErr('Error: setting target', failedTa, 'in', dKey, 'ended with ex:', e) } + try { for (const tar of tars) { const outVal = tar._j ? dmJsos(exprVal) : exprVal; const nextVal = tar.isSi ? combineActResult(getSiVal(tar), outVal, tar._m) : combineActResult(getElPrVal(tar._el || el, tar.path), outVal, tar._m); if (tar.isSi) setSiAndNotifySubsNDeep(dKey, tar, nextVal); else setPr(el, dKey, tar, nextVal) } } + catch (e) { logErr('setting target in', dKey, 'ended with ex:', e) } } } if (!trigs.length) { if (hasExpr) fn(DM, el, null, null, null); return } let ran = false @@ -999,7 +948,7 @@ if (!ran && tr.isImmediate != false) ran = true, invokeBoundSub(sub) continue } - if (!tr.isEv && !tr.isSp) return logErr('Error: unsupported trigger kind', tr.kind, 'in', dKey) + if (!tr.isEv && !tr.isSp) return logErr('bad trigger kind', tr.kind, 'in', dKey) const prTa = tr.isEv && getTrPrTa(el, dKey, tr, mod, E_TRIG_EL, E_TRIG_EV, false) if (tr.isEv && !prTa) return if ((ran = addNonSiTrSub(el, tr, mod, fn, elSubs, ran, prTa)) == null) return @@ -1009,10 +958,10 @@ // - data-m-cl+active+!inactive@is-active="dm.isActive" const dmCl = (el, dKey, dVal) => { const it = parseCached(dKey), adds = it[ADD], tars = it[TARG], trigs = it[TRIG], globMods = it[MOD] - if (!adds.length) return logErr('Error: dmCl requires class names via + syntax in:', dKey) - if (!trigs.length) return logErr('Error: dmCl requires at least one trigger in:', dKey) + if (!adds.length) return logErr('dmCl needs class names via +:', dKey) + if (!trigs.length) return logErr('dmCl needs trigger:', dKey) const taEl = getTaFromTars(el, dKey, tars) - if (!taEl) return logErr('Error: dmCl target element not found in:', dKey) + if (!taEl) return logErr('dmCl target not found:', dKey) const fn = dVal ? compileFn(dVal, dKey) : null if (dVal && !fn) return const elSubs = upsert(_cleanupBoundSubs, el) @@ -1032,9 +981,9 @@ // - data-m-sh:.@is-visible="!dm.isVisible" const dmSh = (el, dKey, dVal) => { const it = parseCached(dKey), tars = it[TARG], trigs = it[TRIG], globMods = it[MOD] - if (!trigs.length) return logErr('Error: dmSh requires at least one trigger in:', dKey) + if (!trigs.length) return logErr('dmSh needs trigger:', dKey) const taEl = getTaFromTars(el, dKey, tars) - if (!taEl) return logErr('Error: dmSh target element not found in:', dKey) + if (!taEl) return logErr('dmSh target not found:', dKey) const inline = (taEl.style && taEl.style.display) || '' const computed = getComputedDisplay(taEl) const origDisp = inline ? inline : (computed === 'none' || !computed ? 'block' : computed) @@ -1104,11 +1053,11 @@ for (const k in tar) if (hasOwn(tar, k)) dmSet(k, tar[k], dKey) return tar } - if (tar?.kind) { if (tar.kind !== SI) return logErr('dmSet signal target expected:', tar, dKey), null } + if (tar?.kind) { if (tar.kind !== SI) return logErr('dmSet target expected:', tar, dKey), null } else { - if (typeof tar !== 'string' || !tar) return logErr('dmSet signal target expected:', tar, dKey), null + if (typeof tar !== 'string' || !tar) return logErr('dmSet target expected:', tar, dKey), null tar = parseCached(getApiDKey(tar, tar[0] === ':' ? 'si' : 'si:'))[TARG][0] - if (tar?.kind !== SI) return logErr('dmSet signal target expected:', tar, dKey), null + if (tar?.kind !== SI) return logErr('dmSet target expected:', tar, dKey), null } setSiAndNotifySubsNDeep(dKey, tar, val) return val @@ -1146,17 +1095,17 @@ // - data-m-it+#tpl-post@posts const dmIt = (el, dKey) => { const it = parseCached(dKey), trigs = it[TRIG], adds = it[ADD], globMods = it[MOD] - if (!trigs.length) return logErr('Error: dmIt requires a signal trigger in:', dKey) + if (!trigs.length) return logErr('dmIt needs signal trigger:', dKey) const tr = trigs[0] - if (!tr.isSi) return logErr('Error: dmIt trigger must be a signal in:', dKey) + if (!tr.isSi) return logErr('dmIt trigger must be signal:', dKey) const mod = compileTrMods(tr, globMods) let tpl = null if (adds.length && adds[0].isEv && adds[0].root) tpl = getElById(adds[0].root, dKey) if (!tpl) tpl = el.querySelector('template') if (tpl && tpl.parentNode === el) tpl.parentNode.removeChild(tpl) - if (!tpl) return logErr('Error: dmIt template not found for:', dKey) + if (!tpl) return logErr('dmIt tpl not found:', dKey) const tplFirst = tpl.content && tpl.content.firstElementChild - if (!tplFirst) return logErr('Error: dmIt template root not found for:', dKey) + if (!tplFirst) return logErr('dmIt tpl root not found:', dKey) let itState = IT_STATES.get(el) if (!itState) IT_STATES.set(el, itState = { nodes: [], count: 0 }) const itemRefBase = buildItRefBase(tr.root, tr.path) @@ -1170,7 +1119,7 @@ const dmAct = (el, dKey, dVal) => { const afterData = dKey.slice(DM_KEY.length), methodEnd = indexFirst(afterData, ALL, 0) const method = ACT_METHODS[methodEnd >= 0 ? afterData.slice(0, methodEnd) : afterData] - if (!method) return logErr('Error: dmAct: unrecognised method prefix in:', dKey) + if (!method) return logErr('dmAct bad method:', dKey) const it = parseCached(dKey), tars = it[TARG], trigs = it[TRIG], adds = it[ADD], globMods = it[MOD] const urlFn = dVal ? compileFn(dVal, dKey) : null if (dVal && !urlFn) return @@ -1240,60 +1189,35 @@ else if (p && p.isSi) actHdrMods.push([camelToKebab(p.path ? p.path.at(-1) : p.root), null, p]) } const ss = (k, v) => actStats && setSiAndNotifySubsNDeep(dKey, actStats[k], v) + const hasAdds = adds.length > 0, hasRouteMods = actRouteMods.length > 0 const doRequest = async () => { const url = urlFn ? urlFn(DM, el, null, null, null) : '' - if (!url) return logErr('Error: dmAct: URL is empty in:', dKey) + if (!url) return logErr('dmAct empty URL:', dKey) ss(M_BUSY, true), ss(M_COMPLETE, false), ss(M_ERR, null), ss(M_CODE, null) try { const queryParams = noProto(), bodyFields = noProto(), addDst = isGetOrDelete ? queryParams : bodyFields if (sendAll) for (const [siName, siVal] of _dm.entries()) bodyFields[siName] = siVal - for (const add of adds) { + if (hasAdds) for (const add of adds) { const val = add.isEv ? getElPrVal(add.taEl || el, add.path) : getSiValOrIt(add) if (add.spread) { if (val && typeof val === 'object') for (const k in val) if (hasOwn(val, k)) addDst[k] = val[k] else addDst.value = val } else addDst[add.key] = val } - for (const [isBody, key, path, ref] of actRouteMods) (isBody ? bodyFields : queryParams)[key] = ref ? getSiValOrIt(ref) : _dm.get(path) + if (hasRouteMods) for (const [isBody, key, path, ref] of actRouteMods) (isBody ? bodyFields : queryParams)[key] = ref ? getSiValOrIt(ref) : _dm.get(path) let finalUrl = url, hasQ = finalUrl.includes('?') for (const k in queryParams) finalUrl += (hasQ ? '&' : '?') + encodeURIComponent(k) + '=' + encodeURIComponent('' + (queryParams[k] ?? '')), hasQ = true let hs = ACT_HS_EMPTY, sharedHs = 1 - if (hdrsPath) { - const hdrObj = resolveMPathVal(hdrsPath) - if (isPlainObj(hdrObj)) { - hs = noProto() - sharedHs = 0 - for (const hk in hdrObj) if (hasOwn(hdrObj, hk)) hs[hsNoKebab ? hk : camelToKebab(hk)] = '' + hdrObj[hk] - } - } - if (baseHs !== ACT_HS_EMPTY) { - if (hs === ACT_HS_EMPTY) hs = baseHs - else for (const hk in baseHs) if (hasOwn(baseHs, hk)) hs[hk] = baseHs[hk] - } - if (authPath != null) { - const authVal = resolveMPathVal(authPath) - if (authVal != null) { - if (sharedHs) hs = cloneOwnProps(hs), sharedHs = 0 - hs[H_AUTHORIZATION] = '' + authVal - } - } - for (const [kebabKey, path, ref] of actHdrMods) { - if (sharedHs) hs = cloneOwnProps(hs), sharedHs = 0 - const v = ref ? getSiValOrIt(ref) : _dm.get(path) - hs[kebabKey] = v != null ? '' + v : '' - } - let bodyCount = 0, firstBodyKey = null + if (hdrsPath) { const hdrObj = resolveMPathVal(hdrsPath); if (isPlainObj(hdrObj)) { hs = noProto(); sharedHs = 0; for (const hk in hdrObj) if (hasOwn(hdrObj, hk)) hs[hsNoKebab ? hk : camelToKebab(hk)] = '' + hdrObj[hk] } } + if (baseHs !== ACT_HS_EMPTY) { if (hs === ACT_HS_EMPTY) hs = baseHs; else for (const hk in baseHs) if (hasOwn(baseHs, hk)) hs[hk] = baseHs[hk] } + if (authPath != null) { const authVal = resolveMPathVal(authPath); if (authVal != null) { if (sharedHs) hs = cloneOwnProps(hs), sharedHs = 0; hs[H_AUTHORIZATION] = '' + authVal } } + for (const [kebabKey, path, ref] of actHdrMods) { if (sharedHs) hs = cloneOwnProps(hs), sharedHs = 0; const v = ref ? getSiValOrIt(ref) : _dm.get(path); hs[kebabKey] = v != null ? '' + v : '' } + let bodyCount = 0, firstBodyKey = null, body = null for (const bk in bodyFields) if (hasOwn(bodyFields, bk)) { if (!bodyCount) firstBodyKey = bk; bodyCount++ } - let body = null if (bodyCount) { const raw = bodyCount === 1 ? bodyFields[firstBodyKey] : bodyFields - if (isForm && (isPlainObj(raw) || Array.isArray(raw))) { - const params = new URLSearchParams() - if (Array.isArray(raw)) for (let i = 0; i < raw.length; i++) params.append('' + i, '' + (raw[i] ?? '')) - else for (const k in raw) if (hasOwn(raw, k)) params.append(k, '' + (raw[k] ?? '')) - body = params.toString() - } else if (isJson || isPlainObj(raw) || Array.isArray(raw)) body = JSON.stringify(raw) - else body = '' + raw + if (isForm && (isPlainObj(raw) || Array.isArray(raw))) { const params = new URLSearchParams(); if (Array.isArray(raw)) for (let i = 0; i < raw.length; i++) params.append('' + i, '' + (raw[i] ?? '')); else for (const k in raw) if (hasOwn(raw, k)) params.append(k, '' + (raw[k] ?? '')); body = params.toString() } + else body = isJson || isPlainObj(raw) || Array.isArray(raw) ? JSON.stringify(raw) : '' + raw } const ac = typeof AbortController !== 'undefined' ? new AbortController() : null activeAbort = ac ? () => ac.abort() : null @@ -1315,12 +1239,14 @@ payload = await res.text() const mode = htmlDomMod?.root || M_OUTER const hp = htmlDomMod && htmlDomMod.path, elTaRoot = hp ? '' : (findFirstKind(tars, EP)?.root ?? '') - const selector = hp ? resolveHtmlSelector(hp) : (mode === M_BEFORE || mode === M_AFTER) ? (el.id ? '#' + el.id : '') : (mode === M_APPEND || mode === M_PREPEND) ? (elTaRoot ? '#' + elTaRoot : '') : '' + let selector = '' + if (hp) { const v = resolveMPathVal(hp); if (typeof v === 'string' && v) { selector = SEL_LEADS.includes(v[0]) ? v : '#' + v } } + else selector = (mode === M_BEFORE || mode === M_AFTER) ? (el.id ? '#' + el.id : '') : (mode === M_APPEND || mode === M_PREPEND) ? (elTaRoot ? '#' + elTaRoot : '') : '' applyPatchEls({ [SSE_ELS]: payload, selector, mode }) } else { payload = isJsonContentType(ct) ? await res.json() : await res.text() - applyActPayload(dKey, resultTa, payload, resultMode) - if (patchAll) patchMatchingSis(dKey, payload, resultMode) + if (resultTa) { const prev = getSiValOrIt(resultTa); setSiAndNotifySubsNDeep(dKey, resultTa, combineActResult(prev, payload, resultMode)) } + if (patchAll && isPlainObj(payload)) for (const key in payload) if (hasOwn(payload, key)) { const root = kebabToCamel(key); if (_dm.has(root)) setSiAndNotifySubsNDeep(dKey, mkIt(SI, null, root, null), combineActResult(_dm.get(root), payload[key], resultMode)) } } ss(M_BUSY, false), ss(M_COMPLETE, true), ss(M_ERR, null), ss(M_CODE, Number.isFinite(res.status) ? res.status : null), ss(M_ABORT, null) activeAbort = null @@ -1343,7 +1269,7 @@ for (const tr of trigs) { if (!tr.isSi && !tr.isEv && !tr.isSp) return logErr('dmAct bad trigger:', tr.kind, dKey) if (tr.isSp) { - if (!tr.sp?.act) return logErr('Error: dmAct unsupported SP trigger', tr.root, 'in', dKey) + if (!tr.sp?.act) return logErr('dmAct unsupported SP', tr.root, 'in', dKey) if (!ran) ran = true, doRequest() continue } @@ -1354,9 +1280,9 @@ continue } const evTaEl = tr.root ? getElById(tr.root, dKey) : el - if (!evTaEl) return logErr('Error: dmAct element not found in trigger:', tr, 'in:', dKey) + if (!evTaEl) return logErr('dmAct el not found:', tr, 'in:', dKey) const ev = tr.path?.[0] ?? getDefaultEv(evTaEl) - if (!ev) return logErr('Error: dmAct event not found in trigger:', tr, 'in:', dKey) + if (!ev) return logErr('dmAct event not found:', tr, 'in:', dKey) const moddedHandler = addTrSub(el, tr, mod, doRequest, elSubs, evTaEl, ev, null, null, evTaEl) if (!ran && tr.isImmediate) ran = true, invokeSub(moddedHandler, null, getElPrVal(evTaEl, null), el, tr) } @@ -1366,7 +1292,7 @@ const dmActApi = (el, dKey, dVal) => bindAddedSubs(el, (host) => dmAct(host, getApiDKey(dKey, ''), dVal)) const WC_TMPLS = new WeakSet(), WC_INITS = new WeakSet() const defWc = (tpl, name) => { - if (!name || name.indexOf('-') < 0) return logErr('dmWc template expects custom-element name value:', name) + if (!name || name.indexOf('-') < 0) return logErr('dmWc needs custom-element name:', name) if (customElements.get(name) || WC_TMPLS.has(tpl)) return WC_TMPLS.add(tpl) const props = (tpl.getAttribute(DM_KEY + 'wc-props') || '').match(/[^,\s]+/g) || NIL @@ -1375,7 +1301,7 @@ customElements.define(name, WC) } // - - const dmWc = (el, dKey, dVal) => el.tagName === 'TEMPLATE' ? defWc(el, dVal && dVal.trim()) : logErr('Error: dmWc is template-only; use data-m-ex for WC host props in:', dKey) + const dmWc = (el, dKey, dVal) => el.tagName === 'TEMPLATE' ? defWc(el, dVal && dVal.trim()) : logErr('dmWc template-only, use data-m-ex for host props:', dKey) const dmNo = () => {} globalThis.dmAct = dmActApi dataM.si = dmSi; dataM.ex = dmEx; dataM.it = dmIt; dataM.wc = dmWc; dataM.cl = dmCl; dataM.sh = dmSh; dataM.dbg = dmDbg; dataM.no = dmNo @@ -1400,19 +1326,15 @@ const getPatchTars = (selector, simpleId = selector && getSimpleIdSelector(selector), el = simpleId && document.getElementById(simpleId)) => !selector ? NIL : simpleId ? el ? [el] : NIL : document.querySelectorAll(selector) const sameAttrs = (from, to) => { - const fromAttrs = from.attributes, toAttrs = to.attributes, len = toAttrs.length - if (fromAttrs.length !== len) return false - for (let i = 0; i < len; i++) { - const fromAttr = fromAttrs[i], toAttr = toAttrs[i] - if (fromAttr.name !== toAttr.name || fromAttr.value !== toAttr.value) return false - } + const fa = from.attributes, ta = to.attributes, len = ta.length + if (fa.length !== len) return false + for (let i = 0; i < len; i++) if (fa[i].name !== ta[i].name || fa[i].value !== ta[i].value) return false return true } - // Sync attributes from to onto from. + // Sync attributes from to onto from. Called only when attrs differ. const updateAttrs = (from, to) => { const toAttrs = to.attributes, fromAttrs = from.attributes, tl = toAttrs.length, fl = fromAttrs.length - if (!fl && !tl) return if (fl === tl) { let same = true, re = false for (let i = 0; i < tl; i++) { @@ -1430,14 +1352,8 @@ if (same) return } } - if (!tl) { - for (let i = fl - 1; i >= 0; i--) from.removeAttribute(fromAttrs[i].name) - return - } - for (let i = 0; i < tl; i++) { - const ta = toAttrs[i], fa = fromAttrs.getNamedItem(ta.name) - if (!fa || fa.value !== ta.value) from.setAttribute(ta.name, ta.value) - } + if (!tl) { for (let i = fl - 1; i >= 0; i--) from.removeAttribute(fromAttrs[i].name); return } + for (let i = 0; i < tl; i++) { const ta = toAttrs[i]; if (fromAttrs.getNamedItem(ta.name)?.value !== ta.value) from.setAttribute(ta.name, ta.value) } for (let i = fl - 1; i >= 0; i--) if (!to.hasAttribute(fromAttrs[i].name)) from.removeAttribute(fromAttrs[i].name) } @@ -1495,7 +1411,7 @@ } let _morphActiveEl = null - const doneMorph = (root) => root && (_morphActiveEl = null) + const _endMorph = (root) => root && (_morphActiveEl = null) // Update from in place without disturbing matched-node listeners or cleanup state. // Preserve caret, selection, and scroll across streamed updates. const morph = (from, to) => { @@ -1503,36 +1419,33 @@ if (root) _morphActiveEl = document.activeElement if (from.nodeType === 3 && to.nodeType === 3) { if (from.nodeValue !== to.nodeValue) from.nodeValue = to.nodeValue - return doneMorph(root) + return _endMorph(root) } - if (from.nodeType !== ELEMENT_NODE || to.nodeType !== ELEMENT_NODE || noMorph(from) || noMorph(to)) return doneMorph(root) + if (from.nodeType !== ELEMENT_NODE || to.nodeType !== ELEMENT_NODE || noMorph(from) || noMorph(to)) return _endMorph(root) if (from.tagName !== to.tagName) { if (from.parentNode) from.parentNode.replaceChild(to.cloneNode(true), from) - return doneMorph(root) + return _endMorph(root) } const fromFirst = from.firstChild, toFirst = to.firstChild, textOnly = fromFirst && toFirst && !fromFirst.nextSibling && !toFirst.nextSibling && fromFirst.nodeType === TEXT_NODE && toFirst.nodeType === TEXT_NODE - if (sameAttrs(from, to) && (!fromFirst && !toFirst || textOnly && fromFirst.nodeValue === toFirst.nodeValue)) return doneMorph(root) - const tag = from.tagName, isFocused = from === _morphActiveEl + const attrsMatch = sameAttrs(from, to) + if (attrsMatch && (!fromFirst && !toFirst || textOnly && fromFirst.nodeValue === toFirst.nodeValue)) return _endMorph(root) + if (textOnly && attrsMatch && from !== _morphActiveEl) { fromFirst.nodeValue = toFirst.nodeValue; return _endMorph(root) } + const isFocused = from === _morphActiveEl let selStart = -1, selEnd = -1, selDir = 'none', selVal = null, selIdx = -1 - if (isFocused && (tag === 'INPUT' || tag === 'TEXTAREA')) { - try { selStart = from.selectionStart; selEnd = from.selectionEnd; selDir = from.selectionDirection || 'none' } catch (_) {} - } else if (isFocused && tag === 'SELECT') selVal = from.value, selIdx = from.selectedIndex - const scrollTop = from.scrollTop, scrollLeft = from.scrollLeft, keepScroll = scrollTop || scrollLeft - updateAttrs(from, to) - if (textOnly) { - if (fromFirst.nodeValue !== toFirst.nodeValue) fromFirst.nodeValue = toFirst.nodeValue - } else if (fromFirst || toFirst) morphChildren(from, to) - if (keepScroll) { - if (from.scrollTop !== scrollTop) from.scrollTop = scrollTop - if (from.scrollLeft !== scrollLeft) from.scrollLeft = scrollLeft - } - if (isFocused && selStart >= 0) { - try { from.setSelectionRange(selStart, selEnd, selDir) } catch (_) {} - } else if (isFocused && tag === 'SELECT') { - from.value = selVal - if (from.value !== selVal && selIdx >= 0 && selIdx < from.options.length) from.selectedIndex = selIdx - } - doneMorph(root) + if (isFocused) { + const tag = from.tagName + if (tag === 'INPUT' || tag === 'TEXTAREA') { + try { selStart = from.selectionStart; selEnd = from.selectionEnd; selDir = from.selectionDirection || 'none' } catch (_) {} + } else if (tag === 'SELECT') selVal = from.value, selIdx = from.selectedIndex + } + const scrollTop = from.scrollTop, scrollLeft = from.scrollLeft + if (!attrsMatch) updateAttrs(from, to) + if (textOnly) { if (fromFirst.nodeValue !== toFirst.nodeValue) fromFirst.nodeValue = toFirst.nodeValue } + else if (fromFirst || toFirst) morphChildren(from, to) + if (scrollTop || scrollLeft) { if (from.scrollTop !== scrollTop) from.scrollTop = scrollTop; if (from.scrollLeft !== scrollLeft) from.scrollLeft = scrollLeft } + if (isFocused && selStart >= 0) { try { from.setSelectionRange(selStart, selEnd, selDir) } catch (_) {} } + else if (isFocused && selVal !== null) { from.value = selVal; if (from.value !== selVal && selIdx >= 0 && selIdx < from.options.length) from.selectedIndex = selIdx } + _endMorph(root) } const JSON_MERGE_DELETE = Symbol('json_merge_delete') @@ -1559,13 +1472,6 @@ return root ? Array.from(root.children) : [] } - const insertFragRelative = (taEl, srcEls, mode) => { - if (!taEl || !srcEls || !srcEls.length) return - const frag = document.createDocumentFragment(), before = mode === M_PREPEND ? taEl.firstChild || null : mode === M_BEFORE ? taEl : taEl.nextSibling - for (const src of srcEls) frag.appendChild(src.cloneNode(true)) - if (mode === M_APPEND) taEl.appendChild(frag) - else (mode === M_PREPEND ? taEl : taEl.parentNode)?.insertBefore(frag, before) - } const applyPatchPair = (taEl, srcEl, mode, reuse = false) => { if (!taEl || !srcEl) return if (mode === M_REPLACE) taEl.replaceWith(reuse ? srcEl : srcEl.cloneNode(true)) @@ -1587,12 +1493,16 @@ const srcEls = parseSseEls(rawEls, ns) if (mode === M_REMOVE) { if (sel) for (const t of document.querySelectorAll(sel)) t.remove() - else for (const src of srcEls) src.id ? document.getElementById(src.id)?.remove() : warn('patch-elements remove needs ids without selector') + else for (const src of srcEls) src.id ? document.getElementById(src.id)?.remove() : warn('patch remove needs ids without selector') return } if (mode === M_APPEND || mode === M_PREPEND || mode === M_BEFORE || mode === M_AFTER) { if (!sel || !srcEls.length) return - for (const t of document.querySelectorAll(sel)) insertFragRelative(t, srcEls, mode) + for (const t of document.querySelectorAll(sel)) { + const frag = document.createDocumentFragment(), before = mode === M_PREPEND ? t.firstChild || null : mode === M_BEFORE ? t : t.nextSibling + for (const src of srcEls) frag.appendChild(src.cloneNode(true)) + if (mode === M_APPEND) t.appendChild(frag); else (mode === M_PREPEND ? t : t.parentNode)?.insertBefore(frag, before) + } return } @@ -1611,7 +1521,7 @@ if (!srcEls.length) return for (const src of srcEls) { if (src.id) applyPatchPair(document.getElementById(src.id), src, mode, true) - else warn('patch-elements needs ids without selector') + else warn('patch needs ids without selector') } } @@ -1631,7 +1541,7 @@ const raw = args[SSE_SIS] if (!raw) return let patchObj = null - try { patchObj = JSON.parse(raw) } catch (_) { return logErr('Error: patch sigs in', dKey, 'expect JSON but found invalid format') } + try { patchObj = JSON.parse(raw) } catch (_) { return logErr('patch sigs in', dKey, 'expect JSON but found invalid format') } if (!isPlainObj(patchObj)) return const onlyIfMissing = (args.onlyIfMissing || '').toLowerCase() === 'true' for (const root in patchObj) if (hasOwn(patchObj, root)) { diff --git a/package.json b/package.json index 02e16b0..4969610 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "dependencies": { "jsdom": "^27.4.0", - "terser": "^5.47.1" + "terser": "^5.48.0" }, "scripts": { "vendor:libs": "node tools/vendor-libs.js", diff --git a/tests/dmax.size.limits.json b/tests/dmax.size.limits.json index f6d6f98..cc01aa3 100644 --- a/tests/dmax.size.limits.json +++ b/tests/dmax.size.limits.json @@ -1,4 +1,4 @@ { - "lines": 1755, - "bytes": 89998 + "lines": 1665, + "bytes": 88035 } diff --git a/tests/fuzz.deterministic.js b/tests/fuzz.deterministic.js index 224dbf9..0a2ffd8 100644 --- a/tests/fuzz.deterministic.js +++ b/tests/fuzz.deterministic.js @@ -154,6 +154,12 @@ function* generateDataSubCombinations() { yield { attr: 'data-m-ex@posts^with_shape', valid: true, category: 'with-shape-sub' } yield { attr: 'data-m-ex@items[0]^with_shape', valid: true, category: 'indexed-shape-sub' } yield { attr: 'data-m-ex:user^merge@ui', valid: true, category: 'target-merge' } + yield { + attr: 'data-m-ex:.text-content^jsos@foo', valid: true, category: 'target-jsos', html: '
    ', exercise: async ({ document }) => { + const text = document.getElementById('fuzz-test').textContent + if (text !== '0') throw new Error('expected ^jsos to stringify signal value, got: ' + text) + } + } yield { attr: 'data-m-ex:.text-content^append@foo', valid: true, category: 'target-append', html: '
    old
    ', exercise: async ({ document }) => { if (document.getElementById('fuzz-test').textContent !== 'old0') throw new Error('expected ^append string write') @@ -190,7 +196,7 @@ function* generateDataSubCombinations() { for (const special of SPECIAL_EVENTS) yield { attr: `data-m-ex:foo@${special}`, valid: true, category: 'special-trigger' } for (const special of SPECIAL_EVENTS_WITH_IO) - yield { attr: `data-m-ex:foo@${special}`, valid: false, category: 'special-trigger-no-io', expectedLog: 'warn', logPattern: 'IntersectionObserver missing, skip _viewed' } + yield { attr: `data-m-ex:foo@${special}`, valid: false, category: 'special-trigger-no-io', expectedLog: 'warn', logPattern: 'no IntersectionObserver' } yield { attr: 'data-m-ex+extra@foo', valid: false, category: 'unsupported-add-warning', expectedLog: 'warn', logPattern: 'targets/triggers/mods only' } @@ -241,14 +247,14 @@ function* generateDataClassCombinations() { yield { attr: 'data-m-cl:+active@is-active', valid: true, category: 'single-class' }; yield { attr: 'data-m-cl+active+!inactive@is-active', valid: true, category: 'inverse-class' }; yield { attr: 'data-m-cl:+foo:+bar@baz', valid: true, category: 'multi-class' }; - yield { attr: 'data-m-cl:', valid: false, category: 'missing-class-error', expectedLog: 'warnOrError', logPattern: 'dmCl requires class names via + syntax' }; + yield { attr: 'data-m-cl:', valid: false, category: 'missing-class-error', expectedLog: 'warnOrError', logPattern: 'dmCl needs class names via +' }; } function* generateDataDispCombinations() { // Valid yield { attr: 'data-m-sh@is-visible', valid: true, category: 'display-signal' }; yield { attr: 'data-m-sh@flag', valid: true, category: 'display-flag' }; - yield { attr: 'data-m-sh:', valid: false, category: 'missing-trigger-error', expectedLog: 'warnOrError', logPattern: 'dmSh requires at least one trigger' }; + yield { attr: 'data-m-sh:', valid: false, category: 'missing-trigger-error', expectedLog: 'warnOrError', logPattern: 'dmSh needs trigger' }; } function* generateDataDumpCombinations() { @@ -260,7 +266,10 @@ function* generateDataDumpCombinations() { // Valid - dotted signal paths yield { attr: 'data-m-it+#tpl-post@user.posts', valid: true, category: 'dotted-signal' }; yield { attr: 'data-m-it+#tpl-item@app.data.items', valid: true, category: 'deep-dotted' }; - yield { attr: 'data-m-it+#tpl-post', valid: false, category: 'missing-trigger-error', expectedLog: 'warnOrError', logPattern: 'dmIt requires a signal trigger' }; + + // Valid - incremental growth (exercises single-item fast path) + yield { attr: 'data-m-it+#tpl-item@items', valid: true, category: 'single-item-growth' }; + yield { attr: 'data-m-it+#tpl-post', valid: false, category: 'missing-trigger-error', expectedLog: 'warnOrError', logPattern: 'dmIt needs signal trigger' }; } function* generateDataActionCombinations() { diff --git a/tools/minify-dmax.js b/tools/minify-dmax.js index 0cf112c..93e05d4 100644 --- a/tools/minify-dmax.js +++ b/tools/minify-dmax.js @@ -16,12 +16,26 @@ const OUT_BR = path.join(ROOT, 'dist', 'dmax.min.js.br') const src = fs.readFileSync(SRC, 'utf8') const out = await minify(src, { compress: { - passes: 2, + passes: 4, unsafe: true, unsafe_math: true, - pure_getters: true + pure_getters: true, + toplevel: true, + reduce_vars: true, + collapse_vars: true, + inline: 3, + join_vars: true, + hoist_funs: true, + dead_code: true, + sequences: true, + conditionals: true, + comparisons: true, + booleans: true, + loops: true, + if_return: true, + keep_fargs: false, }, - mangle: true, + mangle: { toplevel: true }, format: { comments: false } }) if (!out.code) throw new Error('Minifier returned empty output')