pass-down
Version:
Glue DOM and Custom Elements together.
199 lines (198 loc) âĸ 6.91 kB
JavaScript
import { CE } from 'trans-render/lib/CE.js';
import { NotifyMixin } from 'trans-render/lib/mixins/notify.js';
import { getProp, convert } from 'on-to-me/prop-mixin.js';
import { passVal } from 'on-to-me/to-mixin.js';
import { OnMixin } from 'on-to-me/on-mixin.js';
const ce = new CE();
class PassDownCore extends HTMLElement {
doInit({ observedElement, parseValAs, cloneVal, initEvent }) {
if (observedElement === null) {
console.error('404');
return;
}
const foundInitVal = setInitVal({ parseValAs, cloneVal }, this, observedElement);
if (!foundInitVal && initEvent) {
observedElement.addEventListener(initEvent, e => {
setInitVal({ parseValAs, cloneVal }, this, observedElement);
}, { once: true });
}
}
parseValFromEvent(e) {
const val = this.val || 'target.value';
const valToPass = getProp(e, val.split('.'), this);
return valToPass;
}
parseInitVal(elementToObserve) {
const initVal = this.initVal;
if (initVal === undefined)
return undefined;
return getProp(elementToObserve, initVal.split('.'), this);
}
valFromEvent = (e) => {
const val = this.val || 'target.value';
let valToPass = this.parseValFromEvent(e);
if (valToPass === undefined) {
const target = e.target || this.observedElement;
const attribVal = target.getAttribute(val);
if (attribVal !== null) {
valToPass = attribVal;
}
}
if (this.parseValAs) {
valToPass = convert(valToPass, this.parseValAs);
}
valToPass = getBoolVal(valToPass, this);
return this.cloneVal ? structuredClone(valToPass) : valToPass;
};
doEvent({ lastEvent, noblock, valFromEvent }) {
this.setAttribute('status', 'đŠī¸');
if (!noblock && lastEvent.stopPropagation)
lastEvent.stopPropagation();
let valToPass = valFromEvent(lastEvent);
this.lastVal = valToPass;
//holding on to lastEvent could introduce memory leak
this.lastEvent = undefined; //wtf? why does't delete work?
this.setAttribute('status', 'đ');
}
handleValChange({ lastVal, prop, to, careOf, m, from, as, observedElement, propFromTarget, debug, log }) {
if (lastVal === undefined)
return; //do not use falsy gatekeeper for this!
if (debug) {
debugger;
}
else if (log) {
const self = this;
console.log('passVal', { lastVal, self });
}
let dynProp = prop;
if (propFromTarget !== undefined) {
dynProp = getProp(observedElement, propFromTarget.split('.'), this);
}
const matches = passVal(lastVal, this, to, careOf, m, from, dynProp, as);
this.setAttribute('matches', '' + matches.length);
this.cnt++;
}
onFromProp(initVal) {
return this.on === undefined ? ce.toLisp(initVal) + '-changed' : this.on;
}
setValFromTarget({ valFromTarget }) {
if (valFromTarget === undefined)
return;
const initVal = valFromTarget === '' ? 'value' : valFromTarget;
const val = 'target.' + initVal;
const on = this.onFromProp(initVal);
return { on, val, initVal };
}
;
setAliases({ vft }) {
if (vft === undefined)
return;
this.valFromTarget = vft;
}
}
const stringProp = {
type: 'String',
};
const filters = ['isC', 'disabled'];
export const PassDown = await ce.def({
config: {
tagName: 'pass-down',
propDefaults: {
initDelay: 16,
isC: true,
disabled: false,
debug: false,
log: false,
m: Infinity,
cloneVal: false,
noblock: false,
observeHost: false,
trueVal: '',
falseVal: '',
cnt: 0,
},
propChangeMethod: 'onPropChange',
propInfo: {
disabled: {
notify: {
toggleTo: 'enabled',
toggleDelay: 'initDelay',
}
},
lastVal: {
dry: false,
},
enabled: {
type: 'Boolean',
parse: false,
},
cnt: {
notify: {
reflect: {
asAttr: true
}
}
},
on: stringProp, initEvent: stringProp, parseValAs: stringProp, observe: stringProp, initVal: stringProp, ifTargetMatches: stringProp,
val: stringProp, propFromTarget: stringProp, to: stringProp, careOf: stringProp, from: stringProp, prop: stringProp, as: stringProp,
mutateEvents: stringProp, valFromTarget: stringProp, vft: stringProp, observeClosest: stringProp,
},
actions: {
doInit: {
ifAllOf: ['initVal', 'isC', 'enabled'],
ifKeyIn: ['initEvent', 'parseValAs', 'cloneVal'],
},
locateAndListen: {
ifAllOf: ['isC', 'enabled'],
ifKeyIn: ['on', 'onProp', 'observe', 'ifTargetMatches', 'observeHost', 'observeClosest'],
},
doEvent: {
ifAllOf: ['isC', 'lastEvent', 'enabled'],
ifKeyIn: ['val', 'parseValAs', 'noblock'],
},
handleValChange: {
ifAllOf: ['isC', 'enabled'],
ifKeyIn: ['lastVal', 'debug', 'log', 'm', 'propFromTarget', 'to', 'careOf', 'from', 'prop', 'as', 'isC', 'enabled'],
},
attachMutationEventHandler: {
ifAllOf: ['mutateEvents', 'isC', 'enabled'],
},
setValFromTarget: {
ifAllOf: ['isC', 'enabled'],
ifKeyIn: ['valFromTarget'],
},
setAliases: {
ifKeyIn: ['vft'],
}
},
style: {
display: 'none'
}
},
superclass: PassDownCore,
mixins: [NotifyMixin, OnMixin]
});
function getBoolVal(val, { trueVal, falseVal }) {
let valToPass = val;
if (typeof valToPass === 'boolean') {
if (valToPass && trueVal) {
valToPass = trueVal;
}
else if (!valToPass && falseVal) {
valToPass = falseVal;
}
}
return valToPass;
}
function setInitVal({ parseValAs, cloneVal }, self, elementToObserve) {
let val = self.parseInitVal(elementToObserve);
if (val === undefined)
return false;
if (parseValAs)
val = convert(val, parseValAs);
if (cloneVal)
val = structuredClone(val);
val = getBoolVal(val, self);
self.lastVal = val;
return true;
}