From 5436e50a95769cf3247fbca626f9ffc076f24b18 Mon Sep 17 00:00:00 2001 From: Jan Andrle Date: Wed, 13 Sep 2023 13:02:17 +0200 Subject: [PATCH] =?UTF-8?q?:sparkles:=20:bug:=20Try=20to=20make=20`undefin?= =?UTF-8?q?ed`=20more=20inuitive=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …(as it is ‘template lang’ not only `assign`) --- src/dom-common.js | 18 ++++++++++++++++++ src/dom.js | 7 +++---- src/helpers.js | 1 + src/jsdom.js | 8 ++++++++ src/signals-common.js | 3 +-- test/components/webComponent.js | 1 + test/index-nosignals.html | 7 ++++++- 7 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 src/dom-common.js diff --git a/src/dom-common.js b/src/dom-common.js new file mode 100644 index 0000000..94c1af5 --- /dev/null +++ b/src/dom-common.js @@ -0,0 +1,18 @@ +/** @type {Map} */ +export const prop_cache= new Map(JSON.parse('[["#text,textContent",true],["HTMLElement,textContent",true],["HTMLElement,className",true]]')); +export const prop_process= { setDelete }; +import { isUndef } from './helpers.js'; +function setDelete(obj, prop, val){ + /* Issue + For some native attrs you can unset only to set empty string. + This can be confusing as it is seen in inspector `<… id=""`. + Options: + 1. Leave it, as it is native behaviour + 2. Sets as empty string and removes the corresponding attribute when also has empty string + *3. Sets as undefined and removes the corresponding attribute when "undefined" string discovered + 4. Point 2. with checks for coincidence (e.g. use special string) + */ + Reflect.set(obj, prop, val); + if(isUndef(val) && obj.getAttribute(prop)==="undefined") + obj.removeAttribute(prop); +} diff --git a/src/dom.js b/src/dom.js index 47c3c54..888abf6 100644 --- a/src/dom.js +++ b/src/dom.js @@ -30,8 +30,8 @@ export function createElement(tag, attributes, ...connect){ } export { createElement as el }; -/** @type {Map} */ -const prop_cache= new Map(JSON.parse('[["#text,textContent",true],["HTMLElement,textContent",true],["HTMLElement,className",true]]')); +import { prop_cache, prop_process } from './dom-common.js'; +const { setDelete }= prop_process; export function assign(element, ...attributes){ const s= signals(this); if(!attributes.length) return element; @@ -82,6 +82,7 @@ export function empty(el){ Array.from(el.children).forEach(el=> el.remove()); return el; } +import { isUndef } from "./helpers.js"; function isPropSetter(el, key){ const cache_key_he= "HTMLElement,"+key; if(el instanceof HTMLElement && prop_cache.has(cache_key_he)) @@ -104,8 +105,6 @@ function getPropDescriptor(p, key, level= 0){ /** @template {Record} T @param {T} obj @param {(param: [ keyof T, T[keyof T] ])=> void} cb */ function forEachEntries(obj, cb){ return Object.entries(obj).forEach(([ key, val ])=> cb(key, val)); } -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.set(obj, prop, val); } diff --git a/src/helpers.js b/src/helpers.js index f72083f..80c2ee2 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,3 +1,4 @@ +export function isUndef(value){ return typeof value==="undefined"; } export function typeOf(v){ const t= typeof v; if(t!=="object") return t; diff --git a/src/jsdom.js b/src/jsdom.js index 6a580b8..0b6f32a 100644 --- a/src/jsdom.js +++ b/src/jsdom.js @@ -1,3 +1,11 @@ +import { prop_process } from './dom-common.js'; +const { setDelete }= prop_process; +/** @param {HTMLElement} obj */ +prop_process.setDelete= function(obj, prop, value){ + if("checked"!==prop) return setDelete(obj, prop, value); + if(value) return obj.setAttribute("checked", ""); + obj.removeAttribute("checked"); +} const keys= [ "HTMLElement", "SVGElement", "DocumentFragment", "MutationObserver", "document" ]; let dom_last; export let el; diff --git a/src/signals-common.js b/src/signals-common.js index c8029cc..84581a5 100644 --- a/src/signals-common.js +++ b/src/signals-common.js @@ -1,6 +1,5 @@ -import { typeOf } from './helpers.js'; export const signals_global= { - isTextContent(attributes){ return typeOf(attributes)!=="[object Object]"; }, + isTextContent(attributes){ return typeof attributes==="string"; }, processReactiveAttribute(el, key, attr, assignNth){ return attr; }, }; export function registerReactivity(def, global= true){ diff --git a/test/components/webComponent.js b/test/components/webComponent.js index 04ae0c0..d12fe8d 100644 --- a/test/components/webComponent.js +++ b/test/components/webComponent.js @@ -25,6 +25,7 @@ export class CustomHTMLTestElement extends HTMLElement{ ); } } +// https://gist.github.com/WebReflection/ec9f6687842aa385477c4afca625bbf4 customElementsAssign( CustomHTMLTestElement, reflectObservedAttributes, diff --git a/test/index-nosignals.html b/test/index-nosignals.html index 4f9cf06..98be4f0 100644 --- a/test/index-nosignals.html +++ b/test/index-nosignals.html @@ -12,7 +12,12 @@