diff --git a/index.js b/index.js index d4732cd..52c6e66 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -[ HTMLElement, DocumentFragment ].forEach(c=> { +[ HTMLElement, SVGElement, DocumentFragment ].forEach(c=> { const { append }= c.prototype; c.prototype.append= function(...els){ append.apply(this, els); return this; }; }); diff --git a/src/dom-common.js b/src/dom-common.js index 9b933c6..1c6b969 100644 --- a/src/dom-common.js +++ b/src/dom-common.js @@ -12,6 +12,7 @@ function setDeleteAttr(obj, prop, val){ */ Reflect.set(obj, prop, val); if(!isUndef(val)) return; + Reflect.deleteProperty(obj, prop); if(obj instanceof HTMLElement && obj.getAttribute(prop)==="undefined") return obj.removeAttribute(prop); if(Reflect.get(obj, prop)==="undefined") diff --git a/src/dom.js b/src/dom.js index 3bdca90..1f9ebec 100644 --- a/src/dom.js +++ b/src/dom.js @@ -44,26 +44,26 @@ export function assign(element, ...attributes){ const is_svg= element instanceof SVGElement; const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute"); - /* jshint maxcomplexity:17 */ + /* jshint maxcomplexity:13 */ Object.entries(Object.assign({}, ...attributes)).forEach(function assignNth([ key, attr ]){ 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(/(aria|data)([A-Z])/.test(key)){ + if(/(aria|data)([A-Z])/.test(key)){//TODO: temporal as aria* exists in Element for some browsers key= key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); return setRemoveAttr(key, attr); } - if("className"===key) key= "class"; + if("className"===key) key= "class";//just optimalization, `isPropSetter` returns false immediately switch(key){ - case "href": case "src": case "class": - return setRemoveAttr(key, attr); case "xlink:href": return setRemoveAttr(key, attr, "http://www.w3.org/1999/xlink"); - case "textContent": case "innerText": - if(!is_svg) return setDeleteAttr(element, key, attr); - return element.appendChild(document.createTextNode(attr)); - case "style": case "dataset": + case "textContent": //just optimalization, its part of Node ⇒ deep for `isPropSetter` + return setDeleteAttr(element, key, attr); + case "style": + if(typeof attr!=="object") break; + /* falls through */ + case "dataset": return forEachEntries(s, attr, setDelete.bind(null, element[key])); case "ariaset": return forEachEntries(s, attr, (key, val)=> setRemoveAttr("aria-"+key, val)); @@ -86,22 +86,23 @@ export function empty(el){ return el; } import { isUndef } from "./helpers.js"; +//TODO add cache? `Map` function isPropSetter(el, key){ if(!Reflect.has(el, key)) return false; const des= getPropDescriptor(el, key); return !isUndef(des.set); } -function getPropDescriptor(p, key, level= 0){ +function getPropDescriptor(p, key){ p= Object.getPrototypeOf(p); if(!p) return {}; const des= Object.getOwnPropertyDescriptor(p, key); - if(!des) return getPropDescriptor(p, key, level+1); + if(!des) return getPropDescriptor(p, key); return des; } /** @template {Record} T @param {object} s @param {T} obj @param {(param: [ keyof T, T[keyof T] ])=> void} cb */ function forEachEntries(s, obj, cb){ - if(typeof obj !== "object") return; + if(typeof obj !== "object" || obj===null) return; return Object.entries(obj).forEach(function process([ key, val ]){ if(!key) return; val= s.processReactiveAttribute(obj, key, val, a=> cb(...a));