mirror of
https://github.com/jaandrle/deka-dom-el
synced 2025-07-01 20:32:13 +02:00
🚧 types, linting, caching
♻️ add linting to codebase ♻️ Update prototype methods 🐛 update maxcomplexity in jshintConfig ♻️ Improve DOM element property handling ♻️ update setDelete function ✨ Add type annotation for signals() ♻️ Cleanup when signal removed
This commit is contained in:
28
src/dom.js
28
src/dom.js
@ -1,5 +1,6 @@
|
||||
import { signals } from "./signals-common.js";
|
||||
|
||||
/** @type {"html"|"svg"|string} */
|
||||
let namespace_curr= "html";
|
||||
export function namespace(namespace){
|
||||
namespace_curr= namespace==="svg" ? "http://www.w3.org/2000/svg" : namespace;
|
||||
@ -29,22 +30,24 @@ export function createElement(tag, attributes, ...connect){
|
||||
}
|
||||
export { createElement as el };
|
||||
|
||||
const prop_cache= new Map();
|
||||
/** @type {Map<string, boolean>} */
|
||||
const prop_cache= new Map(JSON.parse('[["#text,textContent",true],["HTMLElement,textContent",true],["HTMLElement,className",true]]'));
|
||||
export function assign(element, ...attributes){
|
||||
const s= signals(this);
|
||||
if(!attributes.length) return element;
|
||||
const is_svg= element instanceof SVGElement;
|
||||
const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute");
|
||||
|
||||
/* jshint maxcomplexity:15 */
|
||||
Object.entries(Object.assign({}, ...attributes)).forEach(function assignNth([ key, attr ]){
|
||||
if(s.isReactiveAtrribute(attr, key))
|
||||
attr= s.processReactiveAttribute(el, key, attr, assignNth);
|
||||
attr= s.processReactiveAttribute(element, key, attr, assignNth);
|
||||
const [ k ]= key;
|
||||
if("="===k) return setRemoveAttr(key.slice(1), attr);
|
||||
if("."===k) return setDelete(element, key.slice(1), attr);
|
||||
if(typeof attr === "object"){
|
||||
switch(key){
|
||||
case "style": return forEachEntries(attr, setRemove.bind(null, element.style, "Property"))
|
||||
case "style": return forEachEntries(attr, setRemove.bind(null, element.style, "Property"));
|
||||
case "dataset": return forEachEntries(attr, setDelete.bind(null, element.dataset));
|
||||
case "ariaset": return forEachEntries(attr, (key, val)=> setRemoveAttr("aria-"+key, val));
|
||||
case "classList": return classListDeclartive(element, attr);
|
||||
@ -71,7 +74,7 @@ export function classListDeclartive(element, toggle){
|
||||
|
||||
forEachEntries(toggle,
|
||||
(class_name, val)=>
|
||||
element.classList.toggle(class_name, val===-1 ? undefined : Boolean(val)))
|
||||
element.classList.toggle(class_name, val===-1 ? undefined : Boolean(val)));
|
||||
return element;
|
||||
}
|
||||
export function empty(el){
|
||||
@ -79,18 +82,23 @@ export function empty(el){
|
||||
return el;
|
||||
}
|
||||
function isPropSetter(el, key){
|
||||
const cache_key_he= "HTMLElement,"+key;
|
||||
if(el instanceof HTMLElement && prop_cache.has(cache_key_he))
|
||||
return prop_cache.get(cache_key_he);
|
||||
const cache_key= el.nodeName+","+key;
|
||||
if(prop_cache.has(cache_key)) return prop_cache.get(cache_key);
|
||||
const des= getPropDescriptor(el, key);
|
||||
const [ des, level, p ]= getPropDescriptor(el, key);
|
||||
const is_set= !isUndef(des.set);
|
||||
prop_cache.set(cache_key, is_set);
|
||||
if(!is_set || level)
|
||||
prop_cache.set(p===HTMLElement.prototype ? cache_key_he : cache_key, is_set);
|
||||
return is_set;
|
||||
}
|
||||
function getPropDescriptor(p, key){
|
||||
function getPropDescriptor(p, key, level= 0){
|
||||
p= Object.getPrototypeOf(p);
|
||||
if(!p) return {};
|
||||
if(!p) return [ {}, level, p ];
|
||||
const des= Object.getOwnPropertyDescriptor(p, key);
|
||||
return des ? des : getPropDescriptor(p, key);
|
||||
if(!des) return getPropDescriptor(p, key, level+1);
|
||||
return [ des, level, p ];
|
||||
}
|
||||
|
||||
function forEachEntries(obj, cb){ return Object.entries(obj).forEach(([ key, val ])=> cb(key, val)); }
|
||||
@ -98,4 +106,4 @@ function isUndef(value){ return typeof value==="undefined"; }
|
||||
|
||||
function setRemove(obj, prop, key, val){ return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, val); }
|
||||
function setRemoveNS(obj, prop, key, val, ns= null){ return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, val); }
|
||||
function setDelete(obj, prop, val){ return Reflect[ isUndef(val) ? "deleteProperty" : "set" ](obj, prop, val); }
|
||||
function setDelete(obj, prop, val){ return Reflect.set(obj, prop, val); }
|
||||
|
@ -3,13 +3,14 @@ export const signals_global= {
|
||||
isReactiveAtrribute(attr, key){ return false; },
|
||||
isTextContent(attributes){ return typeOf(attributes)!=="[object Object]"; },
|
||||
processReactiveAttribute(el, key, attr, assignNth){ return false; },
|
||||
reactiveElement(attributes, ...connect){ return document.createDocumentFragment(); }
|
||||
reactiveElement(attributes, ...connect){ return null; }
|
||||
};
|
||||
export function registerReactivity(def, global= true){
|
||||
if(global) return Object.assign(signals_global, def);
|
||||
Object.setPrototypeOf(def, signals_global);
|
||||
return def;
|
||||
}
|
||||
/** @param {unknown} _this @returns {typeof signals_global} */
|
||||
export function signals(_this){
|
||||
return signals_global.isPrototypeOf(_this) && _this!==signals_global ? _this : signals_global;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ S.on= function on(signals, listener, options){
|
||||
if(options && options.signal)
|
||||
options.signal.addEventListener("abort", ()=> removeSignalListener(signals, listener));
|
||||
//TODO cleanup when signal removed (also TODO)
|
||||
}
|
||||
};
|
||||
S.clear= function(...signals){
|
||||
for(const signal of signals){
|
||||
signal[mark].listeners.clear();
|
||||
@ -100,7 +100,7 @@ export function watch(context){
|
||||
stack_watch.push(contextReWatch);
|
||||
context();
|
||||
stack_watch.pop();
|
||||
};
|
||||
}
|
||||
function currentContext(){
|
||||
return stack_watch[stack_watch.length - 1];
|
||||
}
|
||||
@ -116,7 +116,7 @@ function write(signal, value){
|
||||
const s= signal[mark];
|
||||
if(s.value===value) return;
|
||||
s.value= value;
|
||||
s.listeners.forEach(fn=> fn(value))
|
||||
s.listeners.forEach(fn=> fn(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user