Skip to content

Commit

Permalink
Added ?boolean=${value} to explicitly define the developer intent.
Browse files Browse the repository at this point in the history
This comes from latest uhtml as a way to disambiguate explicitly boolean attributes.

https://github.com/WebReflection/uhtml#v24-update

No matter if the value is truthy or falsy, the new syntax will work as expected without ever causing surprises, as it is now for weird cases with Custom Elements or fancy truthy or falsy values.
  • Loading branch information
WebReflection committed Feb 17, 2021
1 parent 11346da commit ac14025
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 60 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,12 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR

- - -

### 2.34 Highlights

* the new `?boolean=${value}` syntax from [µhtml](https://github.com/WebReflection/uhtml#readme) has landed in *hyperHTML* too. Feel free to [rea this long discussion](https://github.com/WebReflection/discussions/discussions/13) to better understand *why* this syntax is necessary.

### V2.5 Highlights

* `<self-closing />` tags for both custom elements and any other as well 🎉

### V2 Highlights
Expand Down
14 changes: 14 additions & 0 deletions cjs/objects/Updates.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ const asNode = (item, i) => {
// returns true if domdiff can handle the value
const canDiff = value => 'ELEMENT_NODE' in value;

// borrowed from uhandlers
// https://github.com/WebReflection/uhandlers
const booleanSetter = (node, key, oldValue) => newValue => {
if (oldValue !== !!newValue) {
if ((oldValue = !!newValue))
node.setAttribute(key, '');
else
node.removeAttribute(key);
}
};

const hyperSetter = (node, name, svg) => svg ?
value => {
try {
Expand Down Expand Up @@ -115,6 +126,9 @@ Tagger.prototype = {
// direct accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '.')
return hyperSetter(node, name.slice(1), isSVG);
// boolean accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '?')
return booleanSetter(node, name.slice(1));
// the name is an event one,
// add/remove event listeners accordingly
else if (/^on/.test(name)) {
Expand Down
2 changes: 1 addition & 1 deletion esm.js

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions esm/objects/Updates.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ const asNode = (item, i) => {
// returns true if domdiff can handle the value
const canDiff = value => 'ELEMENT_NODE' in value;

// borrowed from uhandlers
// https://github.com/WebReflection/uhandlers
const booleanSetter = (node, key, oldValue) => newValue => {
if (oldValue !== !!newValue) {
if ((oldValue = !!newValue))
node.setAttribute(key, '');
else
node.removeAttribute(key);
}
};

const hyperSetter = (node, name, svg) => svg ?
value => {
try {
Expand Down Expand Up @@ -115,6 +126,9 @@ Tagger.prototype = {
// direct accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '.')
return hyperSetter(node, name.slice(1), isSVG);
// boolean accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '?')
return booleanSetter(node, name.slice(1));
// the name is an event one,
// add/remove event listeners accordingly
else if (/^on/.test(name)) {
Expand Down
125 changes: 68 additions & 57 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,16 @@ var hyperHTML = (function (document) {

var canDiff = function canDiff(value) {
return 'ELEMENT_NODE' in value;
}; // borrowed from uhandlers
// https://github.com/WebReflection/uhandlers


var booleanSetter = function booleanSetter(node, key, oldValue) {
return function (newValue) {
if (oldValue !== !!newValue) {
if (oldValue = !!newValue) node.setAttribute(key, '');else node.removeAttribute(key);
}
};
};

var hyperSetter = function hyperSetter(node, name, svg) {
Expand Down Expand Up @@ -1556,77 +1566,78 @@ var hyperHTML = (function (document) {
// handle it differently from others

if (name === 'style') return hyperStyle(node, original, isSVG); // direct accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), isSVG); // the name is an event one,
// add/remove event listeners accordingly
else if (/^on/.test(name)) {
var type = name.slice(2);

if (type === CONNECTED || type === DISCONNECTED) {
observe(node);
} else if (name.toLowerCase() in node) {
type = type.toLowerCase();
}

return function (newValue) {
if (oldValue !== newValue) {
if (oldValue) node.removeEventListener(type, oldValue, false);
oldValue = newValue;
if (newValue) node.addEventListener(type, newValue, false);
else if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), isSVG); // boolean accessors for <input .value=${...}> and friends
else if (name.slice(0, 1) === '?') return booleanSetter(node, name.slice(1)); // the name is an event one,
// add/remove event listeners accordingly
else if (/^on/.test(name)) {
var type = name.slice(2);

if (type === CONNECTED || type === DISCONNECTED) {
observe(node);
} else if (name.toLowerCase() in node) {
type = type.toLowerCase();
}
};
} // the attribute is special ('value' in input)
// and it's not SVG *or* the name is exactly data,
// in this case assign the value directly
else if (name === 'data' || !isSVG && name in node && !readOnly.test(name)) {
return function (newValue) {
if (oldValue !== newValue) {
oldValue = newValue;

if (node[name] !== newValue && newValue == null) {
// cleanup on null to avoid silly IE/Edge bug
node[name] = '';
node.removeAttribute(name);
} else node[name] = newValue;
}
};
} else if (name in Intent.attributes) {
return function (any) {
var newValue = Intent.attributes[name](node, any);

return function (newValue) {
if (oldValue !== newValue) {
if (oldValue) node.removeEventListener(type, oldValue, false);
oldValue = newValue;
if (newValue == null) node.removeAttribute(name);else node.setAttribute(name, newValue);
if (newValue) node.addEventListener(type, newValue, false);
}
};
} // in every other case, use the attribute node as it is
// update only the value, set it as node only when/if needed
else {
var owner = false;
var attribute = original.cloneNode(true);
} // the attribute is special ('value' in input)
// and it's not SVG *or* the name is exactly data,
// in this case assign the value directly
else if (name === 'data' || !isSVG && name in node && !readOnly.test(name)) {
return function (newValue) {
if (oldValue !== newValue) {
oldValue = newValue;

if (attribute.value !== newValue) {
if (newValue == null) {
if (owner) {
owner = false;
node.removeAttributeNode(attribute);
}

attribute.value = newValue;
} else {
attribute.value = newValue;
if (node[name] !== newValue && newValue == null) {
// cleanup on null to avoid silly IE/Edge bug
node[name] = '';
node.removeAttribute(name);
} else node[name] = newValue;
}
};
} else if (name in Intent.attributes) {
return function (any) {
var newValue = Intent.attributes[name](node, any);

if (!owner) {
owner = true;
node.setAttributeNode(attribute);
if (oldValue !== newValue) {
oldValue = newValue;
if (newValue == null) node.removeAttribute(name);else node.setAttribute(name, newValue);
}
};
} // in every other case, use the attribute node as it is
// update only the value, set it as node only when/if needed
else {
var owner = false;
var attribute = original.cloneNode(true);
return function (newValue) {
if (oldValue !== newValue) {
oldValue = newValue;

if (attribute.value !== newValue) {
if (newValue == null) {
if (owner) {
owner = false;
node.removeAttributeNode(attribute);
}

attribute.value = newValue;
} else {
attribute.value = newValue;

if (!owner) {
owner = true;
node.setAttributeNode(attribute);
}
}
}
}
}
};
}
};
}
},
// in a hyper(node)`<div>${content}</div>` case
// everything could happen:
Expand Down
2 changes: 1 addition & 1 deletion min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion umd.js

Large diffs are not rendered by default.

0 comments on commit ac14025

Please sign in to comment.