phlex-reactive 0.15.1 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +89 -0
- data/README.md +72 -9
- data/app/controllers/phlex/reactive/actions_controller.rb +4 -1
- data/app/javascript/phlex/reactive/compute.js +14 -1
- data/app/javascript/phlex/reactive/compute.min.js +2 -2
- data/app/javascript/phlex/reactive/compute.min.js.map +3 -3
- data/app/javascript/phlex/reactive/core.min.js +6 -5
- data/app/javascript/phlex/reactive/core.min.js.map +3 -3
- data/app/javascript/phlex/reactive/features/bindings.js +47 -0
- data/app/javascript/phlex/reactive/features/bindings.min.js +2 -2
- data/app/javascript/phlex/reactive/features/bindings.min.js.map +3 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js +4 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +4 -4
- data/app/javascript/phlex/reactive/runtime.js +337 -13
- data/lib/phlex/reactive/component/helpers.rb +15 -0
- data/lib/phlex/reactive/component/media_binding.rb +85 -0
- data/lib/phlex/reactive/held_fields.rb +87 -0
- data/lib/phlex/reactive/js.rb +142 -29
- data/lib/phlex/reactive/streamable.rb +26 -2
- data/lib/phlex/reactive/test_helpers.rb +11 -2
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +3 -1
|
@@ -377,6 +377,7 @@ function showSyncEnabled(c) {
|
|
|
377
377
|
const nodes = c.root.querySelectorAll?.(SHOW_BINDING_SELECTOR) ?? []
|
|
378
378
|
for (const el of nodes) if (c.core.owns(el)) return true
|
|
379
379
|
for (const el of c.root.querySelectorAll?.(GROUP_BINDING_SELECTOR) ?? []) if (c.core.owns(el)) return true
|
|
380
|
+
for (const el of c.root.querySelectorAll?.(MEDIA_BINDING_SELECTOR) ?? []) if (c.core.owns(el)) return true
|
|
380
381
|
return false
|
|
381
382
|
}
|
|
382
383
|
|
|
@@ -466,6 +467,7 @@ function syncShow(c) {
|
|
|
466
467
|
// The group bindings (issue #319) and the cross-root pass (issue #164)
|
|
467
468
|
// share the same owned-field memo, so a field driving several reads once.
|
|
468
469
|
if (c.groups) syncGroups(c, fieldValue, owns, scope)
|
|
470
|
+
syncMedia(c, fieldValue, owns)
|
|
469
471
|
syncShowTargets(c, fieldValue)
|
|
470
472
|
syncGroupTargets(c, fieldValue)
|
|
471
473
|
}
|
|
@@ -635,6 +637,51 @@ function fieldResolver(c, owns) {
|
|
|
635
637
|
}
|
|
636
638
|
}
|
|
637
639
|
|
|
640
|
+
// --- Media bindings (issue #373) ---------------------------------------------
|
|
641
|
+
// data-reactive-media='{"field","take"?,"pool","label"?,"blank"?}' on a preview
|
|
642
|
+
// <img>: the owned field's value (its first `take` characters, or all of it)
|
|
643
|
+
// is a key into `pool`, whose value is a SELECTOR for an <img> inside the root.
|
|
644
|
+
// The core's copyMedia copies that element's src, srcset and alt — a pool
|
|
645
|
+
// value is never assigned to anything. A key, selector or element that misses
|
|
646
|
+
// clears the preview; `label` gets the alt (or `blank`) via textContent. An
|
|
647
|
+
// unowned field leaves the preview alone (the show default-deny); a malformed
|
|
648
|
+
// attr warns and is skipped.
|
|
649
|
+
const MEDIA_BINDING_SELECTOR = "[data-reactive-media]"
|
|
650
|
+
|
|
651
|
+
function syncMedia(c, fieldValue, owns) {
|
|
652
|
+
for (const el of c.root.querySelectorAll(MEDIA_BINDING_SELECTOR)) {
|
|
653
|
+
if (!owns(el)) continue
|
|
654
|
+
let wire
|
|
655
|
+
try {
|
|
656
|
+
wire = JSON.parse(el.getAttribute("data-reactive-media"))
|
|
657
|
+
} catch {}
|
|
658
|
+
if (typeof wire?.field !== "string" || !wire.pool || typeof wire.pool !== "object") {
|
|
659
|
+
console.warn("[phlex-reactive] malformed data-reactive-media — skipped")
|
|
660
|
+
continue
|
|
661
|
+
}
|
|
662
|
+
const value = fieldValue(wire.field)
|
|
663
|
+
if (value === null) continue
|
|
664
|
+
// Characters (code points), as Ruby counts them — not UTF-16 code units.
|
|
665
|
+
const key = wire.take > 0 ? [...value].slice(0, wire.take).join("") : value
|
|
666
|
+
const source = Object.hasOwn(wire.pool, key) ? mediaMatches(c, wire.pool[key])[0] : null
|
|
667
|
+
const alt = c.core.copyMedia(el, source ?? null)
|
|
668
|
+
if (alt === null || typeof wire.label !== "string") continue
|
|
669
|
+
const text = alt === false ? String(wire.blank ?? "") : alt
|
|
670
|
+
for (const node of mediaMatches(c, wire.label)) if (node.textContent !== text) node.textContent = text
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// The owned elements a pool or label selector names — none when it does not
|
|
675
|
+
// parse (a URL string is not a selector), and none for the "@root" sentinel:
|
|
676
|
+
// a label naming the root would rewrite the whole root's text.
|
|
677
|
+
function mediaMatches(c, selector) {
|
|
678
|
+
try {
|
|
679
|
+
return selector === "@root" ? [] : c.core.opTargets({ to: selector })
|
|
680
|
+
} catch {
|
|
681
|
+
return []
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
638
685
|
// --- Bulk selection (issue #319) ---------------------------------------------
|
|
639
686
|
// A checkbox GROUP is the owned boxes sharing one name. Three bindings read it:
|
|
640
687
|
// the select-all header (data-reactive-select-all), the ticked count
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{confirmPredicate as oe}from"phlex/reactive/confirm_predicate";var g=new WeakMap,q=new WeakMap;function p(e,r){let t=g.get(e);if(!t){if(g.set(e,t={root:e.element,core:r,nestedIndex:0}),t.root)q.set(t.root,t)}return t}function d(e,r,t){for(let n of r.split(" "))e.root.addEventListener?.(n,t),e.offs.push(()=>e.root.removeEventListener?.(n,t))}function y(e,r){d(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Pe(e,r){let t=p(e,r);t.offs=[],t.seeds=[];let n,o,i,s;(t.wire=()=>{if(!t.show&&le(t))t.show=(a)=>{if(t.flipping)return;if(a?.type==="input"||a?.type==="change")me(t,a.target);else t.groups=ye(t),T(t);de(t)},d(t,"input change",t.show),y(t,t.show);if(!t.arm&&ue(t))d(t,"input change",(a)=>R(t,a)),y(t,t.arm=()=>{R(t,null),T(t)});if(!n&&(n=t.show||t.arm))d(t,"reset",()=>setTimeout(()=>{if(g.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(!o&&(o=b(t)))d(t,"input",(a)=>be(t,a)&&m(t)),y(t,()=>m(t));if(!i&&(i=S(t)))y(t,()=>H(t));if(!s&&(s=we(t)))d(t,"input change",(a)=>Q(t,a)),y(t,()=>O(t))})(),d(t,"keydown",(a)=>Le(t,a)),d(t,"paste drop",(a)=>Me(t,a)),d(t,"input",(a)=>De(t,a))}function We(e){let r=g.get(e);if(!r)return;g.delete(e),q.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function Ge(e){let r=g.get(e);if(!r)return;for(let t of r.seeds)t();r.wire()}function h(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function Fe(e,r,t){return Q(p(e,r),t)}function Be(e,r,t){return re(p(e,r),t)}var ie=/^#[A-Za-z_][\w-]*$/,M="[data-reactive-show-field], [data-reactive-show]";function se(e,r){let t=e.getAttribute("data-reactive-show-equals");if(t!==null)return r===t;let n=e.getAttribute("data-reactive-show-not");if(n!==null)return r!==n;let o=e.getAttribute("data-reactive-show-in");if(o!==null){try{let i=JSON.parse(o);if(Array.isArray(i))return i.includes(r)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(o)} — skipped`),null}for(let i of Z){let s=e.getAttribute(`data-reactive-show-${i}`);if(s!==null)return ee(i,s,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function D(e){try{let r=JSON.parse(e);if(r&&typeof r==="object"&&!Array.isArray(r))return r}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(e)} — skipped`),null}function ae(e){try{let r=JSON.parse(e);if(Array.isArray(r)&&r.every((t)=>t&&typeof t==="object"&&Array.isArray(t.any)&&Array.isArray(t.ops)))return r}catch{}return console.warn(`[phlex-reactive] malformed reactive_on_complete payload ${JSON.stringify(e)} — skipped`),[]}function I(e,r){if(!e||typeof e!=="object")return null;let t=e.any;if(Array.isArray(t)&&(t.length===0||Array.isArray(t[0])))return v(t,r);return ce(e,r)}function ce(e,r){let t=Array.isArray(e.all)?"all":Array.isArray(e.any)?"any":null;if(!t)return null;let n=e[t];if(n.length===0)return null;let o=n.map((i)=>E(i,r));return t==="all"?o.every(Boolean):o.some(Boolean)}function A(e,r="show"){if(typeof e==="string"&&ie.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function le(e){if(e.root.getAttribute?.("data-reactive-show-targets"))return!0;if(e.root.getAttribute?.("data-reactive-group-targets"))return!0;let r=e.root.querySelectorAll?.(M)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(w)??[])if(e.core.owns(t))return!0;return!1}function ue(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function fe(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:ae(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function R(e,r){let t=fe(e);if(!t.length)return;let n=G(e,e.core.ownership());t.forEach((o,i)=>{let s=v(o.any,n);if(s===null)return;let a=s&&!e.onCompleteStates[i]&&Boolean(r);if(e.onCompleteStates[i]=s,a)e.core.applyOps(o.ops,"@root")})}function de(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,n=G(e,r);for(let o of e.root.querySelectorAll(M)){if(!r(o))continue;let i=o.getAttribute("data-reactive-show");if(i!==null){let c=I(D(i),n);if(c!==null)J(o,c,r,t);continue}let s=o.getAttribute("data-reactive-show-field");if(!s)continue;let a=n(s);if(a===null)continue;let l=se(o,a);if(l===null)continue;J(o,l,r,t)}if(e.groups)ve(e,n,r,t);pe(e,n),Ae(e,n)}function J(e,r,t,n){if(e.hidden=!r,e.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof e.querySelectorAll!=="function")return;for(let o of e.querySelectorAll("input[name], select[name], textarea[name]"))if(t(o))o.disabled=!r;if(e.name&&t(e))e.disabled=!r}function pe(e,r){let t=P(e);for(let[n,o]of Object.entries(t)){if(n.startsWith("#")){ge(n,o,r);continue}if(!o||typeof o!=="object"||Array.isArray(o))continue;let i=r(n);if(i===null)continue;let s=(a,l)=>l?r(n,!0):i;for(let[a,l]of Object.entries(o)){if(!A(a))continue;let c;if(Array.isArray(l)){if(l.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${a} — skipped`);continue}c=l.every((u)=>E(u,s))}else{let u=te(l,i);if(u===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${a} — skipped`);continue}c=u}for(let u of document.querySelectorAll(a))u.hidden=!c}}}function ge(e,r,t){if(!A(e))return;let n=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,o=Je(n);if(o===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(o.every((s)=>t(s)===null)&&!Te(n))return;let i=v(n,t);if(i===null)return;for(let s of document.querySelectorAll(e))s.hidden=!i}function P(e,r="show",t="mode: { ... }, kind: { ... }"){let n=e.root.getAttribute?.(`data-reactive-${r}-targets`);if(!n)return{};try{let o=JSON.parse(n);if(o&&typeof o==="object"&&!Array.isArray(o))return o}catch{}return console.warn(`[phlex-reactive] malformed data-reactive-${r}-targets — ignored. `+`Did two reactive_${r}_targets calls collide on one root? Declare every entry in ONE call: reactive_${r}_targets(${t})`),{}}function he(e,r,t,n){let o=!1,i=null;for(let s of e.root.querySelectorAll(W(r,n))){if(!t(s))continue;if(s.type==="checkbox")return s.checked?"true":"false";if(s.type==="radio"){if(s.checked)return s.value??"";o=!0;continue}i??=s}if(i)return i.value??"";return o?"":null}function W(e,r){return`[name="${r&&!e.includes("[")?`${r}[${e}]`:e}"]`}function G(e,r){let t=e.root.getAttribute?.("data-reactive-scope")||null,n=new Map;return(o,i)=>{let s=i?`#${o}`:o;if(!n.has(s))n.set(s,i?_(e,o,r,t).filter((a)=>a.checked).length:he(e,o,r,t));return n.get(s)}}var w="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function ye(e){return!!e.root.querySelector?.(w)}function _(e,r,t,n){return[...e.root.querySelectorAll(W(r,n))].filter((o)=>o.type==="checkbox"&&t(o))}function me(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))F(e,t,r.checked,r)}function Ke(e,r,t){if(!r)return;let n=q.get(e)??{root:e,core:{ownership:()=>(o)=>o.closest('[data-controller~="reactive"]')===e}};F(n,r,t!==!1),n.show?.()}function F(e,r,t,n){let o=e.root.getAttribute?.("data-reactive-scope")||null,i=_(e,r,e.core.ownership(),o).filter((s)=>s!==n&&s.checked!==t);for(let s of i)s.checked=t;e.flipping=!0;try{for(let s of i)for(let a of["input","change"])s.dispatchEvent?.(new Event(a,{bubbles:!0}))}finally{e.flipping=!1}}function ve(e,r,t,n){for(let o of e.root.querySelectorAll(w)){if(!t(o))continue;let i=o.getAttribute("data-reactive-enable");if(i!==null){let l=I(D(i),r);if(l!==null)o.disabled=!l}let s=o.getAttribute("data-reactive-count");if(s){let l=String(r(s,!0));if(o.textContent!==l)o.textContent=l}let a=o.getAttribute("data-reactive-select-all");if(a){let l=_(e,a,t,n).filter((u)=>u!==o),c=l.filter((u)=>u.checked).length;o.checked=c>0&&c===l.length,o.indeterminate=c>0&&c<l.length}}}function Ae(e,r){for(let[t,n]of Object.entries(P(e,"group",'"ids[]" => { ... }, "tags[]" => { ... }'))){if(!n||typeof n!=="object"||Array.isArray(n))continue;let o=String(r(t,!0));for(let s of Array.isArray(n.count)?n.count:[]){if(!A(s,"group"))continue;for(let a of document.querySelectorAll(s))if(a.textContent!==o)a.textContent=o}let i=n.enable&&typeof n.enable==="object"?n.enable:{};for(let[s,a]of Object.entries(i)){if(!A(s,"group"))continue;let l=v(a?.any,r);if(l===null){console.warn(`[phlex-reactive] malformed reactive_group_targets enable for ${s} — skipped`);continue}for(let c of document.querySelectorAll(s))c.disabled=!l}}}function T(e){if(e.groupObserver||typeof MutationObserver!=="function")return;let r=(o)=>e.root.getAttribute?.(`data-reactive-${o}`)?.includes("checked_");if(!e.root.getAttribute?.("data-reactive-group-targets")&&!e.root.querySelector?.(`${w}, [data-reactive-show*=checked_]`)&&!r("show-targets")&&!r("on-complete"))return;let n=(o)=>o.nodeType===1&&(o.matches('input[type="checkbox"]')||!!o.querySelector('input[type="checkbox"]'));e.groupObserver=new MutationObserver((o)=>{if(!o.some((i)=>[...i.addedNodes,...i.removedNodes].some(n)))return;e.show?.(),e.arm?.()}),e.groupObserver.observe(e.root,{childList:!0,subtree:!0})}function b(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function be(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function m(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.root.getAttribute("data-reactive-filter-input"),t=e.root.getAttribute("data-reactive-filter-option");if(!r||!t)return;let n=e.core.ownership(),o=[...e.root.querySelectorAll(r)].find(n);if(!o)return;let i=(o.value??"").trim().toLowerCase(),s=0;for(let c of e.root.querySelectorAll(t)){if(!n(c))continue;let u=(c.getAttribute("data-reactive-filter-text")??c.textContent??"").toLowerCase(),f=c.hasAttribute?.("data-reactive-tags-selected")||i!==""&&!u.includes(i);if(c.hidden=f,f)c.removeAttribute("data-reactive-highlighted");else s++}let a=e.root.getAttribute("data-reactive-filter-group");if(a)for(let c of e.root.querySelectorAll(a)){if(!n(c))continue;let u=[...c.querySelectorAll(t)].filter(n);if(u.length===0)continue;c.hidden=u.every((f)=>f.hidden)}let l=e.root.getAttribute("data-reactive-filter-empty");if(l){for(let c of e.root.querySelectorAll(l))if(n(c))c.hidden=s>0}}function S(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function we(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function N(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-tags-field");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function k(e){let r=new Set,t=[];for(let n of String(e.value??"").split(",")){let o=n.trim();if(o===""||r.has(o.toLowerCase()))continue;r.add(o.toLowerCase()),t.push(o)}return t}function B(e,r){let t=N(e);if(!t)return!1;let n=k(t),o=new Set(n.map((s)=>s.toLowerCase())),i=!1;for(let s of r){let a=String(s??"").trim();if(a===""||o.has(a.toLowerCase()))continue;o.add(a.toLowerCase()),n.push(a),i=!0}if(i)K(e,t,n);return i}function K(e,r,t){r.value=t.join(","),h(r),H(e)}function Se(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-filter-input");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function H(e){let r=N(e);if(!r)return;let t=k(r),n=e.core.ownership();xe(e,t,n),Ce(e,t,n)}function xe(e,r,t){let n=[...e.root.querySelectorAll("[data-reactive-tags-list]")].find(t);if(!n)return;let i=[...e.root.querySelectorAll("[data-reactive-tags-template]")].find(t)?.content?.firstElementChild;if(!i){if(!e.tagsWarnedTemplate)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),e.tagsWarnedTemplate=!0;return}while(n.firstChild)n.removeChild(n.firstChild);for(let s of r){let a=i.cloneNode(!0);a.setAttribute?.("data-reactive-tag",s);let l=a.matches?.("[data-reactive-tag-text]")?a:(a.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(l)l.textContent=s;let c=[...a.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(a.matches?.('[data-action*="reactive#tagsRemove"]'))c.push(a);for(let u of c)u.setAttribute?.("data-reactive-tag-param",s);n.appendChild(a)}}function Ce(e,r,t){let n=new Set(r.map((o)=>o.toLowerCase()));for(let o of e.root.querySelectorAll("[role=option]")){if(!t(o))continue;let i=o.getAttribute?.("data-reactive-tag-param");if(!i)continue;if(n.has(i.toLowerCase()))o.setAttribute("data-reactive-tags-selected","true"),o.hidden=!0,o.removeAttribute?.("data-reactive-highlighted");else if(o.hasAttribute?.("data-reactive-tags-selected")){if(o.removeAttribute("data-reactive-tags-selected"),!b(e))o.hidden=!1}}if(b(e))m(e)}function qe(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function _e(e,r){let t=[e,...e.querySelectorAll?.("*")??[]];for(let n of t)for(let o of["name","id","for"]){let i=n.getAttribute?.(o);if(i&&i.includes("NEW_ROW"))n.setAttribute?.(o,i.replaceAll("NEW_ROW",String(r)))}}function Ne(e,r){if(e.nestedWarned)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${r}"] container + <template data-reactive-nested-template="${r}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),e.nestedWarned=!0}function ke(e,r,t,n){if(!t)return null;let o;try{o=JSON.parse(t)}catch{return null}if(!o||typeof o!=="object")return null;let i=e.core.ownership(),s=[...r.querySelectorAll?.("input, select, textarea")??[]],a=[];for(let[l,c]of Object.entries(o)){let u=[...e.root.querySelectorAll?.(c)??[]].find(i);if(!u)continue;let f=s.find((x)=>Y(x.getAttribute?.("name"))===l);if(!f)continue;Oe(f,u),a.push(u)}if(n)for(let l of a)Ee(l);return a[0]??null}function Oe(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:C(r)!=="";else e.value=C(r);h(e)}function Ee(e){if(e.type==="checkbox")e.checked=!1;else e.value="";h(e)}function $e(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,n)=>Object.prototype.hasOwnProperty.call(r,n)?r[n]:t)}function L(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",h(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);O(e)}function O(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership();for(let t of[...e.root.querySelectorAll("[data-reactive-nested-json]")].filter(r))U(e,t.getAttribute("data-reactive-nested-json"))}function je(e,r){let t=r.getAttribute?.("data-reactive-nested-json-field");if(!t)return null;let n=e.core.ownership();return[...e.root.querySelectorAll(t)].find(n)??null}function z(e,r){let t={},n=e.core.ownership();for(let o of[...r.querySelectorAll?.("input, select, textarea")??[]]){if(o.matches(":disabled")||o.type==="radio"&&!o.checked||!n(o))continue;let i=Y(o.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=C(o)}return t}function Y(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function C(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function U(e,r){let t=e.core.ownership(),n=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!n)return;let o=je(e,n);if(!o)return;let i=[];for(let a of[...n.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!t(a)||a.hidden)continue;i.push(z(e,a))}let s=JSON.stringify(i);if(o.value===s)return;o.value=s,h(o)}function He(e,r,t){let n=p(e,r);if(!S(n))return;if(t?.defaultPrevented)return;if(n.core.listnavOptions(t).some((s)=>s.hasAttribute?.("data-reactive-highlighted")))return;t?.preventDefault?.();let o=t?.currentTarget??t?.target;if(!o)return;if(!B(n,String(o.value??"").split(",")))return;if(o.value="",b(n))m(n)}function ze(e,r,t){let n=p(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!B(n,[i]))return;let s=Se(n);if(!s)return;s.value="",m(n),s.focus?.()}function Ye(e,r,t){let n=p(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let s=N(n);if(!s)return;let a=k(s),l=a.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===a.length)return;K(n,s,l)}function Ue(e,r,t){let n=p(e,r);t?.preventDefault?.();let o=t?.currentTarget??t?.target,i=o?.getAttribute?.("data-reactive-association-param");if(!i)return;if(typeof n.root?.querySelectorAll!=="function")return;let s=n.core.ownership(),a=[...n.root.querySelectorAll(`[data-reactive-nested-list="${i}"]`)].find(s),c=[...n.root.querySelectorAll(`[data-reactive-nested-template="${i}"]`)].find(s)?.content?.firstElementChild;if(!a||!c){Ne(n,i);return}let u=c.cloneNode(!0);_e(u,qe(n)),a.appendChild(u);let f=o?.getAttribute?.("data-reactive-nested-from-param"),x=o?.getAttribute?.("data-reactive-nested-clear-param")==="true",ne=ke(n,u,f,x);if(f)ne?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(a.getAttribute?.("data-reactive-nested-json")===i)U(n,i)}function Qe(e,r,t){let n=p(e,r);t?.preventDefault?.();let o=t?.currentTarget??t?.target,i=o?.closest?.("[data-reactive-nested-row]");if(!i)return;if(i.closest?.('[data-controller~="reactive"]')!==n.root)return;let s=o?.getAttribute?.("data-reactive-confirm-param"),a=o?.getAttribute?.("data-reactive-confirm-when-param"),l=s||(a?re(n,a):null);if(!l)return L(n,i);let c=z(n,i),u=$e(l,c);return n.core.confirm(u,{el:o,row:i,fields:c}).then((f)=>{if(f)L(n,i)})}function Q(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;O(e)}var Z=["gte","gt","lte","lt"],Re=["len_eq","len_gte","len_gt","len_lte","len_lt"],V=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function X(e,r,t){if(!Number.isInteger(r))return console.warn(`[phlex-reactive] reactive_show ${e}: needs an integer literal, got ${JSON.stringify(r)} — skipped`),null;switch(e.slice(e.indexOf("_")+1)){case"eq":return t===r;case"gte":return t>=r;case"gt":return t>r;case"lte":return t<=r;case"lt":return t<r;default:return null}}function ee(e,r,t){let n=Number(r);if(Number.isNaN(n))return console.warn(`[phlex-reactive] reactive_show ${e}: needs a numeric literal, got ${JSON.stringify(r)} — skipped`),null;let o=t==null?"":String(t).trim(),i=o===""?NaN:Number(o);if(Number.isNaN(i))return!1;switch(e){case"gte":return i>=n;case"gt":return i>n;case"lte":return i<=n;case"lt":return i<n;default:return null}}function te(e,r){if(!e||typeof e!=="object")return null;if(typeof e.equals==="string")return r===e.equals;if(typeof e.not==="string")return r!==e.not;if(Array.isArray(e.in))return e.in.includes(r);for(let t of Z)if(t in e)return ee(t,e[t],r);for(let t of Re)if(t in e)return X(t,e[t],[...String(r??"")].length);return null}function E(e,r){if(!e||typeof e!=="object"||typeof e.field!=="string")return!1;let t=V.find((o)=>(o in e));if(t){let o=r(e.field,!0);return X(t,e[t],Array.isArray(o)?o.length:Number(o)||0)===!0}let n=r(e.field)??"";return te(e,n)===!0}function v(e,r){if(!Array.isArray(e)||e.length===0)return null;return e.some((t)=>Array.isArray(t)&&t.length>0&&t.every((n)=>E(n,r)))}function Je(e){if(!Array.isArray(e)||e.length===0)return null;let r=new Set;for(let t of e){if(!Array.isArray(t))continue;for(let n of t)if(n&&typeof n==="object"&&typeof n.field==="string")r.add(n.field)}return r.size>0?[...r]:null}function Te(e){return e.flat().every((r)=>V.some((t)=>(t in Object(r))))}function re(e,r){let t=r;if(typeof r==="string")try{t=JSON.parse(r)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(r)} — skipped`),null}if(!t||typeof t!=="object")return null;let{fields:n}=e.core.collectFields(),o=(s)=>n[s],i;if(typeof t.predicate==="string"){let s=oe(t.predicate);if(!s)return console.warn(`[phlex-reactive] confirm predicate "${t.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;i=!!s(n)}else i=v(t.groups?.any,o)===!0;return i?t.message:null}function j(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function Le(e,r){let t=j(e,r);if(!t||r.isComposing||r.keyCode===229)return;if(r.key==="Enter"){let n=t.getAttribute("data-reactive-editable-enter");if(t.getAttribute("data-reactive-editable")==="multi"&&(n==null||r.shiftKey))return;if(r.preventDefault(),n==="submit")t.closest("form")?.requestSubmit();else if(n)e.core.applyOps(JSON.parse(n),"@root")}else if(r.key==="Escape"&&t.hasAttribute("data-reactive-editable-escape"))r.preventDefault(),t.textContent=e.core.served(t),h(t),t.blur()}function Me(e,r){let t=j(e,r),n=t?.getAttribute("data-reactive-editable")!=="multi",o=(r.clipboardData??r.dataTransfer)?.getData("text/plain");if(!t||o==null||e.core.plain()&&!(n&&/[\r\n]/.test(o)))return;if(r.preventDefault(),n)o=o.replace(/\r?\n|\r/g," ");t.focus(),document.execCommand("insertText",!1,o)}function De(e,r){let t=j(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{Ke as checkGroup,Be as confirmMessage,Pe as connect,We as disconnect,Ue as nestedAdd,Qe as nestedRemove,Ge as reseed,Fe as syncNestedJson,He as tagsAdd,ze as tagsPick,Ye as tagsRemove};
|
|
1
|
+
import{confirmPredicate as ae}from"phlex/reactive/confirm_predicate";var g=new WeakMap,q=new WeakMap;function p(e,r){let t=g.get(e);if(!t){if(g.set(e,t={root:e.element,core:r,nestedIndex:0}),t.root)q.set(t.root,t)}return t}function d(e,r,t){for(let o of r.split(" "))e.root.addEventListener?.(o,t),e.offs.push(()=>e.root.removeEventListener?.(o,t))}function y(e,r){d(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Be(e,r){let t=p(e,r);t.offs=[],t.seeds=[];let o,n,i,a;(t.wire=()=>{if(!t.show&&fe(t))t.show=(s)=>{if(t.flipping)return;if(s?.type==="input"||s?.type==="change")Ae(t,s.target);else t.groups=be(t),M(t);ge(t)},d(t,"input change",t.show),y(t,t.show);if(!t.arm&&de(t))d(t,"input change",(s)=>R(t,s)),y(t,t.arm=()=>{R(t,null),M(t)});if(!o&&(o=t.show||t.arm))d(t,"reset",()=>setTimeout(()=>{if(g.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(!n&&(n=A(t)))d(t,"input",(s)=>xe(t,s)&&m(t)),y(t,()=>m(t));if(!i&&(i=S(t)))y(t,()=>Y(t));if(!a&&(a=Ce(t)))d(t,"input change",(s)=>V(t,s)),y(t,()=>O(t))})(),d(t,"keydown",(s)=>Ie(t,s)),d(t,"paste drop",(s)=>Pe(t,s)),d(t,"input",(s)=>We(t,s))}function Fe(e){let r=g.get(e);if(!r)return;g.delete(e),q.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function Ke(e){let r=g.get(e);if(!r)return;for(let t of r.seeds)t();r.wire()}function h(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function He(e,r,t){return V(p(e,r),t)}function ze(e,r,t){return oe(p(e,r),t)}var se=/^#[A-Za-z_][\w-]*$/,D="[data-reactive-show-field], [data-reactive-show]";function ce(e,r){let t=e.getAttribute("data-reactive-show-equals");if(t!==null)return r===t;let o=e.getAttribute("data-reactive-show-not");if(o!==null)return r!==o;let n=e.getAttribute("data-reactive-show-in");if(n!==null){try{let i=JSON.parse(n);if(Array.isArray(i))return i.includes(r)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(n)} — skipped`),null}for(let i of X){let a=e.getAttribute(`data-reactive-show-${i}`);if(a!==null)return re(i,a,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function I(e){try{let r=JSON.parse(e);if(r&&typeof r==="object"&&!Array.isArray(r))return r}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(e)} — skipped`),null}function le(e){try{let r=JSON.parse(e);if(Array.isArray(r)&&r.every((t)=>t&&typeof t==="object"&&Array.isArray(t.any)&&Array.isArray(t.ops)))return r}catch{}return console.warn(`[phlex-reactive] malformed reactive_on_complete payload ${JSON.stringify(e)} — skipped`),[]}function P(e,r){if(!e||typeof e!=="object")return null;let t=e.any;if(Array.isArray(t)&&(t.length===0||Array.isArray(t[0])))return v(t,r);return ue(e,r)}function ue(e,r){let t=Array.isArray(e.all)?"all":Array.isArray(e.any)?"any":null;if(!t)return null;let o=e[t];if(o.length===0)return null;let n=o.map((i)=>E(i,r));return t==="all"?n.every(Boolean):n.some(Boolean)}function b(e,r="show"){if(typeof e==="string"&&se.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function fe(e){if(e.root.getAttribute?.("data-reactive-show-targets"))return!0;if(e.root.getAttribute?.("data-reactive-group-targets"))return!0;let r=e.root.querySelectorAll?.(D)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(w)??[])if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(F)??[])if(e.core.owns(t))return!0;return!1}function de(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function pe(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:le(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function R(e,r){let t=pe(e);if(!t.length)return;let o=B(e,e.core.ownership());t.forEach((n,i)=>{let a=v(n.any,o);if(a===null)return;let s=a&&!e.onCompleteStates[i]&&Boolean(r);if(e.onCompleteStates[i]=a,s)e.core.applyOps(n.ops,"@root")})}function ge(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,o=B(e,r);for(let n of e.root.querySelectorAll(D)){if(!r(n))continue;let i=n.getAttribute("data-reactive-show");if(i!==null){let l=P(I(i),o);if(l!==null)J(n,l,r,t);continue}let a=n.getAttribute("data-reactive-show-field");if(!a)continue;let s=o(a);if(s===null)continue;let c=ce(n,s);if(c===null)continue;J(n,c,r,t)}if(e.groups)we(e,o,r,t);ve(e,o,r),he(e,o),Se(e,o)}function J(e,r,t,o){if(e.hidden=!r,e.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof e.querySelectorAll!=="function")return;for(let n of e.querySelectorAll("input[name], select[name], textarea[name]"))if(t(n))n.disabled=!r;if(e.name&&t(e))e.disabled=!r}function he(e,r){let t=W(e);for(let[o,n]of Object.entries(t)){if(o.startsWith("#")){ye(o,n,r);continue}if(!n||typeof n!=="object"||Array.isArray(n))continue;let i=r(o);if(i===null)continue;let a=(s,c)=>c?r(o,!0):i;for(let[s,c]of Object.entries(n)){if(!b(s))continue;let l;if(Array.isArray(c)){if(c.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${s} — skipped`);continue}l=c.every((u)=>E(u,a))}else{let u=ne(c,i);if(u===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${s} — skipped`);continue}l=u}for(let u of document.querySelectorAll(s))u.hidden=!l}}}function ye(e,r,t){if(!b(e))return;let o=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,n=Le(o);if(n===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(n.every((a)=>t(a)===null)&&!De(o))return;let i=v(o,t);if(i===null)return;for(let a of document.querySelectorAll(e))a.hidden=!i}function W(e,r="show",t="mode: { ... }, kind: { ... }"){let o=e.root.getAttribute?.(`data-reactive-${r}-targets`);if(!o)return{};try{let n=JSON.parse(o);if(n&&typeof n==="object"&&!Array.isArray(n))return n}catch{}return console.warn(`[phlex-reactive] malformed data-reactive-${r}-targets — ignored. `+`Did two reactive_${r}_targets calls collide on one root? Declare every entry in ONE call: reactive_${r}_targets(${t})`),{}}function me(e,r,t,o){let n=!1,i=null;for(let a of e.root.querySelectorAll(G(r,o))){if(!t(a))continue;if(a.type==="checkbox")return a.checked?"true":"false";if(a.type==="radio"){if(a.checked)return a.value??"";n=!0;continue}i??=a}if(i)return i.value??"";return n?"":null}function G(e,r){return`[name="${r&&!e.includes("[")?`${r}[${e}]`:e}"]`}function B(e,r){let t=e.root.getAttribute?.("data-reactive-scope")||null,o=new Map;return(n,i)=>{let a=i?`#${n}`:n;if(!o.has(a))o.set(a,i?_(e,n,r,t).filter((s)=>s.checked).length:me(e,n,r,t));return o.get(a)}}var F="[data-reactive-media]";function ve(e,r,t){for(let o of e.root.querySelectorAll(F)){if(!t(o))continue;let n;try{n=JSON.parse(o.getAttribute("data-reactive-media"))}catch{}if(typeof n?.field!=="string"||!n.pool||typeof n.pool!=="object"){console.warn("[phlex-reactive] malformed data-reactive-media — skipped");continue}let i=r(n.field);if(i===null)continue;let a=n.take>0?[...i].slice(0,n.take).join(""):i,s=Object.hasOwn(n.pool,a)?T(e,n.pool[a])[0]:null,c=e.core.copyMedia(o,s??null);if(c===null||typeof n.label!=="string")continue;let l=c===!1?String(n.blank??""):c;for(let u of T(e,n.label))if(u.textContent!==l)u.textContent=l}}function T(e,r){try{return r==="@root"?[]:e.core.opTargets({to:r})}catch{return[]}}var w="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function be(e){return!!e.root.querySelector?.(w)}function _(e,r,t,o){return[...e.root.querySelectorAll(G(r,o))].filter((n)=>n.type==="checkbox"&&t(n))}function Ae(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))K(e,t,r.checked,r)}function Ye(e,r,t){if(!r)return;let o=q.get(e)??{root:e,core:{ownership:()=>(n)=>n.closest('[data-controller~="reactive"]')===e}};K(o,r,t!==!1),o.show?.()}function K(e,r,t,o){let n=e.root.getAttribute?.("data-reactive-scope")||null,i=_(e,r,e.core.ownership(),n).filter((a)=>a!==o&&a.checked!==t);for(let a of i)a.checked=t;e.flipping=!0;try{for(let a of i)for(let s of["input","change"])a.dispatchEvent?.(new Event(s,{bubbles:!0}))}finally{e.flipping=!1}}function we(e,r,t,o){for(let n of e.root.querySelectorAll(w)){if(!t(n))continue;let i=n.getAttribute("data-reactive-enable");if(i!==null){let c=P(I(i),r);if(c!==null)n.disabled=!c}let a=n.getAttribute("data-reactive-count");if(a){let c=String(r(a,!0));if(n.textContent!==c)n.textContent=c}let s=n.getAttribute("data-reactive-select-all");if(s){let c=_(e,s,t,o).filter((u)=>u!==n),l=c.filter((u)=>u.checked).length;n.checked=l>0&&l===c.length,n.indeterminate=l>0&&l<c.length}}}function Se(e,r){for(let[t,o]of Object.entries(W(e,"group",'"ids[]" => { ... }, "tags[]" => { ... }'))){if(!o||typeof o!=="object"||Array.isArray(o))continue;let n=String(r(t,!0));for(let a of Array.isArray(o.count)?o.count:[]){if(!b(a,"group"))continue;for(let s of document.querySelectorAll(a))if(s.textContent!==n)s.textContent=n}let i=o.enable&&typeof o.enable==="object"?o.enable:{};for(let[a,s]of Object.entries(i)){if(!b(a,"group"))continue;let c=v(s?.any,r);if(c===null){console.warn(`[phlex-reactive] malformed reactive_group_targets enable for ${a} — skipped`);continue}for(let l of document.querySelectorAll(a))l.disabled=!c}}}function M(e){if(e.groupObserver||typeof MutationObserver!=="function")return;let r=(n)=>e.root.getAttribute?.(`data-reactive-${n}`)?.includes("checked_");if(!e.root.getAttribute?.("data-reactive-group-targets")&&!e.root.querySelector?.(`${w}, [data-reactive-show*=checked_]`)&&!r("show-targets")&&!r("on-complete"))return;let o=(n)=>n.nodeType===1&&(n.matches('input[type="checkbox"]')||!!n.querySelector('input[type="checkbox"]'));e.groupObserver=new MutationObserver((n)=>{if(!n.some((i)=>[...i.addedNodes,...i.removedNodes].some(o)))return;e.show?.(),e.arm?.()}),e.groupObserver.observe(e.root,{childList:!0,subtree:!0})}function A(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function xe(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function m(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.root.getAttribute("data-reactive-filter-input"),t=e.root.getAttribute("data-reactive-filter-option");if(!r||!t)return;let o=e.core.ownership(),n=[...e.root.querySelectorAll(r)].find(o);if(!n)return;let i=(n.value??"").trim().toLowerCase(),a=0;for(let l of e.root.querySelectorAll(t)){if(!o(l))continue;let u=(l.getAttribute("data-reactive-filter-text")??l.textContent??"").toLowerCase(),f=l.hasAttribute?.("data-reactive-tags-selected")||i!==""&&!u.includes(i);if(l.hidden=f,f)l.removeAttribute("data-reactive-highlighted");else a++}let s=e.root.getAttribute("data-reactive-filter-group");if(s)for(let l of e.root.querySelectorAll(s)){if(!o(l))continue;let u=[...l.querySelectorAll(t)].filter(o);if(u.length===0)continue;l.hidden=u.every((f)=>f.hidden)}let c=e.root.getAttribute("data-reactive-filter-empty");if(c){for(let l of e.root.querySelectorAll(c))if(o(l))l.hidden=a>0}}function S(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function Ce(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function k(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-tags-field");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function N(e){let r=new Set,t=[];for(let o of String(e.value??"").split(",")){let n=o.trim();if(n===""||r.has(n.toLowerCase()))continue;r.add(n.toLowerCase()),t.push(n)}return t}function H(e,r){let t=k(e);if(!t)return!1;let o=N(t),n=new Set(o.map((a)=>a.toLowerCase())),i=!1;for(let a of r){let s=String(a??"").trim();if(s===""||n.has(s.toLowerCase()))continue;n.add(s.toLowerCase()),o.push(s),i=!0}if(i)z(e,t,o);return i}function z(e,r,t){r.value=t.join(","),h(r),Y(e)}function qe(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-filter-input");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function Y(e){let r=k(e);if(!r)return;let t=N(r),o=e.core.ownership();_e(e,t,o),ke(e,t,o)}function _e(e,r,t){let o=[...e.root.querySelectorAll("[data-reactive-tags-list]")].find(t);if(!o)return;let i=[...e.root.querySelectorAll("[data-reactive-tags-template]")].find(t)?.content?.firstElementChild;if(!i){if(!e.tagsWarnedTemplate)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),e.tagsWarnedTemplate=!0;return}while(o.firstChild)o.removeChild(o.firstChild);for(let a of r){let s=i.cloneNode(!0);s.setAttribute?.("data-reactive-tag",a);let c=s.matches?.("[data-reactive-tag-text]")?s:(s.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(c)c.textContent=a;let l=[...s.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(s.matches?.('[data-action*="reactive#tagsRemove"]'))l.push(s);for(let u of l)u.setAttribute?.("data-reactive-tag-param",a);o.appendChild(s)}}function ke(e,r,t){let o=new Set(r.map((n)=>n.toLowerCase()));for(let n of e.root.querySelectorAll("[role=option]")){if(!t(n))continue;let i=n.getAttribute?.("data-reactive-tag-param");if(!i)continue;if(o.has(i.toLowerCase()))n.setAttribute("data-reactive-tags-selected","true"),n.hidden=!0,n.removeAttribute?.("data-reactive-highlighted");else if(n.hasAttribute?.("data-reactive-tags-selected")){if(n.removeAttribute("data-reactive-tags-selected"),!A(e))n.hidden=!1}}if(A(e))m(e)}function Ne(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function Oe(e,r){let t=[e,...e.querySelectorAll?.("*")??[]];for(let o of t)for(let n of["name","id","for"]){let i=o.getAttribute?.(n);if(i&&i.includes("NEW_ROW"))o.setAttribute?.(n,i.replaceAll("NEW_ROW",String(r)))}}function Ee(e,r){if(e.nestedWarned)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${r}"] container + <template data-reactive-nested-template="${r}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),e.nestedWarned=!0}function $e(e,r,t,o){if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}if(!n||typeof n!=="object")return null;let i=e.core.ownership(),a=[...r.querySelectorAll?.("input, select, textarea")??[]],s=[];for(let[c,l]of Object.entries(n)){let u=[...e.root.querySelectorAll?.(l)??[]].find(i);if(!u)continue;let f=a.find((x)=>Q(x.getAttribute?.("name"))===c);if(!f)continue;je(f,u),s.push(u)}if(o)for(let c of s)Re(c);return s[0]??null}function je(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:C(r)!=="";else e.value=C(r);h(e)}function Re(e){if(e.type==="checkbox")e.checked=!1;else e.value="";h(e)}function Je(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,o)=>Object.prototype.hasOwnProperty.call(r,o)?r[o]:t)}function L(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",h(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);O(e)}function O(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership();for(let t of[...e.root.querySelectorAll("[data-reactive-nested-json]")].filter(r))Z(e,t.getAttribute("data-reactive-nested-json"))}function Te(e,r){let t=r.getAttribute?.("data-reactive-nested-json-field");if(!t)return null;let o=e.core.ownership();return[...e.root.querySelectorAll(t)].find(o)??null}function U(e,r){let t={},o=e.core.ownership();for(let n of[...r.querySelectorAll?.("input, select, textarea")??[]]){if(n.matches(":disabled")||n.type==="radio"&&!n.checked||!o(n))continue;let i=Q(n.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=C(n)}return t}function Q(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function C(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function Z(e,r){let t=e.core.ownership(),o=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!o)return;let n=Te(e,o);if(!n)return;let i=[];for(let s of[...o.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!t(s)||s.hidden)continue;i.push(U(e,s))}let a=JSON.stringify(i);if(n.value===a)return;n.value=a,h(n)}function Ue(e,r,t){let o=p(e,r);if(!S(o))return;if(t?.defaultPrevented)return;if(o.core.listnavOptions(t).some((a)=>a.hasAttribute?.("data-reactive-highlighted")))return;t?.preventDefault?.();let n=t?.currentTarget??t?.target;if(!n)return;if(!H(o,String(n.value??"").split(",")))return;if(n.value="",A(o))m(o)}function Qe(e,r,t){let o=p(e,r);if(!S(o))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!H(o,[i]))return;let a=qe(o);if(!a)return;a.value="",m(o),a.focus?.()}function Ze(e,r,t){let o=p(e,r);if(!S(o))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let a=k(o);if(!a)return;let s=N(a),c=s.filter((l)=>l.toLowerCase()!==i.toLowerCase());if(c.length===s.length)return;z(o,a,c)}function Ve(e,r,t){let o=p(e,r);t?.preventDefault?.();let n=t?.currentTarget??t?.target,i=n?.getAttribute?.("data-reactive-association-param");if(!i)return;if(typeof o.root?.querySelectorAll!=="function")return;let a=o.core.ownership(),s=[...o.root.querySelectorAll(`[data-reactive-nested-list="${i}"]`)].find(a),l=[...o.root.querySelectorAll(`[data-reactive-nested-template="${i}"]`)].find(a)?.content?.firstElementChild;if(!s||!l){Ee(o,i);return}let u=l.cloneNode(!0);Oe(u,Ne(o)),s.appendChild(u);let f=n?.getAttribute?.("data-reactive-nested-from-param"),x=n?.getAttribute?.("data-reactive-nested-clear-param")==="true",ie=$e(o,u,f,x);if(f)ie?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(s.getAttribute?.("data-reactive-nested-json")===i)Z(o,i)}function Xe(e,r,t){let o=p(e,r);t?.preventDefault?.();let n=t?.currentTarget??t?.target,i=n?.closest?.("[data-reactive-nested-row]");if(!i)return;if(i.closest?.('[data-controller~="reactive"]')!==o.root)return;let a=n?.getAttribute?.("data-reactive-confirm-param"),s=n?.getAttribute?.("data-reactive-confirm-when-param"),c=a||(s?oe(o,s):null);if(!c)return L(o,i);let l=U(o,i),u=Je(c,l);return o.core.confirm(u,{el:n,row:i,fields:l}).then((f)=>{if(f)L(o,i)})}function V(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;O(e)}var X=["gte","gt","lte","lt"],Me=["len_eq","len_gte","len_gt","len_lte","len_lt"],ee=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function te(e,r,t){if(!Number.isInteger(r))return console.warn(`[phlex-reactive] reactive_show ${e}: needs an integer literal, got ${JSON.stringify(r)} — skipped`),null;switch(e.slice(e.indexOf("_")+1)){case"eq":return t===r;case"gte":return t>=r;case"gt":return t>r;case"lte":return t<=r;case"lt":return t<r;default:return null}}function re(e,r,t){let o=Number(r);if(Number.isNaN(o))return console.warn(`[phlex-reactive] reactive_show ${e}: needs a numeric literal, got ${JSON.stringify(r)} — skipped`),null;let n=t==null?"":String(t).trim(),i=n===""?NaN:Number(n);if(Number.isNaN(i))return!1;switch(e){case"gte":return i>=o;case"gt":return i>o;case"lte":return i<=o;case"lt":return i<o;default:return null}}function ne(e,r){if(!e||typeof e!=="object")return null;if(typeof e.equals==="string")return r===e.equals;if(typeof e.not==="string")return r!==e.not;if(Array.isArray(e.in))return e.in.includes(r);for(let t of X)if(t in e)return re(t,e[t],r);for(let t of Me)if(t in e)return te(t,e[t],[...String(r??"")].length);return null}function E(e,r){if(!e||typeof e!=="object"||typeof e.field!=="string")return!1;let t=ee.find((n)=>(n in e));if(t){let n=r(e.field,!0);return te(t,e[t],Array.isArray(n)?n.length:Number(n)||0)===!0}let o=r(e.field)??"";return ne(e,o)===!0}function v(e,r){if(!Array.isArray(e)||e.length===0)return null;return e.some((t)=>Array.isArray(t)&&t.length>0&&t.every((o)=>E(o,r)))}function Le(e){if(!Array.isArray(e)||e.length===0)return null;let r=new Set;for(let t of e){if(!Array.isArray(t))continue;for(let o of t)if(o&&typeof o==="object"&&typeof o.field==="string")r.add(o.field)}return r.size>0?[...r]:null}function De(e){return e.flat().every((r)=>ee.some((t)=>(t in Object(r))))}function oe(e,r){let t=r;if(typeof r==="string")try{t=JSON.parse(r)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(r)} — skipped`),null}if(!t||typeof t!=="object")return null;let{fields:o}=e.core.collectFields(),n=(a)=>o[a],i;if(typeof t.predicate==="string"){let a=ae(t.predicate);if(!a)return console.warn(`[phlex-reactive] confirm predicate "${t.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;i=!!a(o)}else i=v(t.groups?.any,n)===!0;return i?t.message:null}function j(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function Ie(e,r){let t=j(e,r);if(!t||r.isComposing||r.keyCode===229)return;if(r.key==="Enter"){let o=t.getAttribute("data-reactive-editable-enter");if(t.getAttribute("data-reactive-editable")==="multi"&&(o==null||r.shiftKey))return;if(r.preventDefault(),o==="submit")t.closest("form")?.requestSubmit();else if(o)e.core.applyOps(JSON.parse(o),"@root")}else if(r.key==="Escape"&&t.hasAttribute("data-reactive-editable-escape"))r.preventDefault(),t.textContent=e.core.served(t),h(t),t.blur()}function Pe(e,r){let t=j(e,r),o=t?.getAttribute("data-reactive-editable")!=="multi",n=(r.clipboardData??r.dataTransfer)?.getData("text/plain");if(!t||n==null||e.core.plain()&&!(o&&/[\r\n]/.test(n)))return;if(r.preventDefault(),o)n=n.replace(/\r?\n|\r/g," ");t.focus(),document.execCommand("insertText",!1,n)}function We(e,r){let t=j(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{Ye as checkGroup,ze as confirmMessage,Be as connect,Fe as disconnect,Ve as nestedAdd,Xe as nestedRemove,Ke as reseed,He as syncNestedJson,Ue as tagsAdd,Qe as tagsPick,Ze as tagsRemove};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=099864F98B8480EC64756E2164756E21
|
|
4
4
|
//# sourceMappingURL=bindings.min.js.map
|