UNPKG

be-consensual

Version:

Provides two-way binding between a checkbox (or other (custom) DOM elements) and surrounding checkboxes (or other (custom) DOM elements).

174 lines (173 loc) 6.36 kB
import { define } from 'be-decorated/DE.js'; import { register } from 'be-hive/register.js'; export class BeConsensualController { async finale(proxy, target, beDecorProps) { const { unsubscribe } = await import('trans-render/lib/subscribe.js'); unsubscribe(proxy); } async onMemberOptions(pp) { console.log('onMemberOptions'); const { proxy, self, memberAttr, debounceDelay, memberProp, memberEvent } = pp; if (!self.id) { self.id = 'a_' + (new Date()).valueOf(); } const id = self.id; const { addCSSListener } = await import('trans-render/lib/observeCssSelector.js'); addCSSListener(id, self, `[${memberAttr}]`, async (e) => { if (e.animationName !== id) return; const target = e.target; target.setAttribute(memberAttr.replace('be-', 'is-'), ''); target.removeAttribute(memberAttr); if (memberEvent !== undefined) { target.addEventListener(memberEvent, e => { if (proxy.downwardFlowInProgress) return; this.evaluateState(pp); }); } else { const { subscribe } = await import('trans-render/lib/subscribe.js'); console.log('subscribe', { target, memberProp }); subscribe(target, memberProp, () => { console.log('onSubscribe'); if (proxy.downwardFlowInProgress) return; this.evaluateState(pp); }); } proxy.matchCount++; setTimeout(() => { proxy.matchCountEcho++; }, debounceDelay); }); } onMatchCountEchoChange(pp) { const { matchCountEcho, matchCount } = pp; if (matchCountEcho !== matchCount) return; this.evaluateState(pp); } getMemberSelector({ memberAttr }) { return '[' + memberAttr.replace('be-', 'is-') + ']'; } async onSelfProp(pp) { const { selfProp, self, selfEvent } = pp; if (selfEvent !== undefined) { self.addEventListener(selfEvent, e => { this.passDown(pp); }); } else { const { subscribe } = await import('trans-render/lib/subscribe.js'); subscribe(self, selfProp, () => { this.passDown(pp); }); } } passDown(pp) { const { selfProp, proxy, memberProp, memberTrueVal, memberFalseVal, selfTrueVal, self, selfEvent } = pp; proxy.downwardFlowInProgress = true; let val; if (proxy[selfProp] === selfTrueVal) { val = memberTrueVal; } else { val = memberFalseVal; } const memberSelector = this.getMemberSelector(pp); proxy.getRootNode().querySelectorAll(memberSelector).forEach((el) => { el[memberProp] = val; }); proxy.downwardFlowInProgress = false; } async evaluateState(pp) { const { memberAttr, memberProp, memberFalseVal, memberTrueVal, proxy } = pp; const memberSelector = this.getMemberSelector(pp); const elements = Array.from(proxy.getRootNode().querySelectorAll(memberSelector)); let hasTrue = false; let hasFalse = false; let isIndeterminate = false; for (const element of elements) { if (element.localName.includes('-')) await customElements.whenDefined(element.localName); const aElement = element; if (aElement[memberProp] === memberTrueVal) { hasTrue = true; } else if (aElement[memberProp] === memberFalseVal) { hasFalse = true; } else { isIndeterminate = true; break; } if (hasTrue && hasFalse) { isIndeterminate = true; break; } } const aProxy = proxy; if (isIndeterminate) { aProxy[proxy.selfIndeterminateProp] = proxy.selfIndeterminateTrueVal; } else if (hasTrue) { aProxy[proxy.selfIndeterminateProp] = proxy.selfIndeterminateFalseVal; aProxy[proxy.selfProp] = proxy.selfTrueVal; } else if (hasFalse) { aProxy[proxy.selfIndeterminateProp] = proxy.selfIndeterminateFalseVal; aProxy[proxy.selfProp] = proxy.selfFalseVal; } } } const tagName = 'be-consensual'; const ifWantsToBe = 'consensual'; const upgrade = '*'; define({ config: { tagName, propDefaults: { ifWantsToBe, upgrade, virtualProps: [ 'memberAttr', 'memberProp', 'memberTrueVal', 'memberFalseVal', 'memberEvent', 'selfEvent', 'selfProp', 'selfTrueVal', 'selfFalseVal', 'selfIndeterminateProp', 'selfIndeterminateTrueVal', 'selfIndeterminateFalseVal', 'matchCount', 'matchCountEcho', 'debounceDelay', 'downwardFlowInProgress' ], proxyPropDefaults: { memberProp: 'checked', memberEvent: 'input', memberTrueVal: true, memberFalseVal: false, memberAttr: 'be-consensual-member', matchCount: 0, matchCountEcho: 0, selfProp: 'checked', selfTrueVal: true, selfFalseVal: false, selfIndeterminateProp: 'indeterminate', selfIndeterminateTrueVal: true, selfIndeterminateFalseVal: false, selfEvent: 'input', downwardFlowInProgress: false, }, finale: 'finale', }, actions: { onMemberOptions: { ifAllOf: ['memberAttr'], }, onMatchCountEchoChange: { ifAllOf: ['matchCount', 'matchCountEcho'], }, onSelfProp: { ifAllOf: ['selfProp', 'memberProp'] } } }, complexPropDefaults: { controller: BeConsensualController } }); register(ifWantsToBe, upgrade, tagName);