Skip to content

Commit ac14025

Browse files
committed
Added ?boolean=${value} to explicitly define the developer intent.
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.
1 parent 11346da commit ac14025

File tree

7 files changed

+103
-60
lines changed

7 files changed

+103
-60
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,12 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR
8383

8484
- - -
8585

86+
### 2.34 Highlights
87+
88+
* 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.
8689

8790
### V2.5 Highlights
91+
8892
* `<self-closing />` tags for both custom elements and any other as well 🎉
8993

9094
### V2 Highlights

cjs/objects/Updates.js

+14
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ const asNode = (item, i) => {
4949
// returns true if domdiff can handle the value
5050
const canDiff = value => 'ELEMENT_NODE' in value;
5151

52+
// borrowed from uhandlers
53+
// https://github.com/WebReflection/uhandlers
54+
const booleanSetter = (node, key, oldValue) => newValue => {
55+
if (oldValue !== !!newValue) {
56+
if ((oldValue = !!newValue))
57+
node.setAttribute(key, '');
58+
else
59+
node.removeAttribute(key);
60+
}
61+
};
62+
5263
const hyperSetter = (node, name, svg) => svg ?
5364
value => {
5465
try {
@@ -115,6 +126,9 @@ Tagger.prototype = {
115126
// direct accessors for <input .value=${...}> and friends
116127
else if (name.slice(0, 1) === '.')
117128
return hyperSetter(node, name.slice(1), isSVG);
129+
// boolean accessors for <input .value=${...}> and friends
130+
else if (name.slice(0, 1) === '?')
131+
return booleanSetter(node, name.slice(1));
118132
// the name is an event one,
119133
// add/remove event listeners accordingly
120134
else if (/^on/.test(name)) {

esm.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esm/objects/Updates.js

+14
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ const asNode = (item, i) => {
4949
// returns true if domdiff can handle the value
5050
const canDiff = value => 'ELEMENT_NODE' in value;
5151

52+
// borrowed from uhandlers
53+
// https://github.com/WebReflection/uhandlers
54+
const booleanSetter = (node, key, oldValue) => newValue => {
55+
if (oldValue !== !!newValue) {
56+
if ((oldValue = !!newValue))
57+
node.setAttribute(key, '');
58+
else
59+
node.removeAttribute(key);
60+
}
61+
};
62+
5263
const hyperSetter = (node, name, svg) => svg ?
5364
value => {
5465
try {
@@ -115,6 +126,9 @@ Tagger.prototype = {
115126
// direct accessors for <input .value=${...}> and friends
116127
else if (name.slice(0, 1) === '.')
117128
return hyperSetter(node, name.slice(1), isSVG);
129+
// boolean accessors for <input .value=${...}> and friends
130+
else if (name.slice(0, 1) === '?')
131+
return booleanSetter(node, name.slice(1));
118132
// the name is an event one,
119133
// add/remove event listeners accordingly
120134
else if (/^on/.test(name)) {

index.js

+68-57
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,16 @@ var hyperHTML = (function (document) {
14911491

14921492
var canDiff = function canDiff(value) {
14931493
return 'ELEMENT_NODE' in value;
1494+
}; // borrowed from uhandlers
1495+
// https://github.com/WebReflection/uhandlers
1496+
1497+
1498+
var booleanSetter = function booleanSetter(node, key, oldValue) {
1499+
return function (newValue) {
1500+
if (oldValue !== !!newValue) {
1501+
if (oldValue = !!newValue) node.setAttribute(key, '');else node.removeAttribute(key);
1502+
}
1503+
};
14941504
};
14951505

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

15581568
if (name === 'style') return hyperStyle(node, original, isSVG); // direct accessors for <input .value=${...}> and friends
1559-
else if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), isSVG); // the name is an event one,
1560-
// add/remove event listeners accordingly
1561-
else if (/^on/.test(name)) {
1562-
var type = name.slice(2);
1563-
1564-
if (type === CONNECTED || type === DISCONNECTED) {
1565-
observe(node);
1566-
} else if (name.toLowerCase() in node) {
1567-
type = type.toLowerCase();
1568-
}
1569-
1570-
return function (newValue) {
1571-
if (oldValue !== newValue) {
1572-
if (oldValue) node.removeEventListener(type, oldValue, false);
1573-
oldValue = newValue;
1574-
if (newValue) node.addEventListener(type, newValue, false);
1569+
else if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), isSVG); // boolean accessors for <input .value=${...}> and friends
1570+
else if (name.slice(0, 1) === '?') return booleanSetter(node, name.slice(1)); // the name is an event one,
1571+
// add/remove event listeners accordingly
1572+
else if (/^on/.test(name)) {
1573+
var type = name.slice(2);
1574+
1575+
if (type === CONNECTED || type === DISCONNECTED) {
1576+
observe(node);
1577+
} else if (name.toLowerCase() in node) {
1578+
type = type.toLowerCase();
15751579
}
1576-
};
1577-
} // the attribute is special ('value' in input)
1578-
// and it's not SVG *or* the name is exactly data,
1579-
// in this case assign the value directly
1580-
else if (name === 'data' || !isSVG && name in node && !readOnly.test(name)) {
1581-
return function (newValue) {
1582-
if (oldValue !== newValue) {
1583-
oldValue = newValue;
1584-
1585-
if (node[name] !== newValue && newValue == null) {
1586-
// cleanup on null to avoid silly IE/Edge bug
1587-
node[name] = '';
1588-
node.removeAttribute(name);
1589-
} else node[name] = newValue;
1590-
}
1591-
};
1592-
} else if (name in Intent.attributes) {
1593-
return function (any) {
1594-
var newValue = Intent.attributes[name](node, any);
15951580

1581+
return function (newValue) {
15961582
if (oldValue !== newValue) {
1583+
if (oldValue) node.removeEventListener(type, oldValue, false);
15971584
oldValue = newValue;
1598-
if (newValue == null) node.removeAttribute(name);else node.setAttribute(name, newValue);
1585+
if (newValue) node.addEventListener(type, newValue, false);
15991586
}
16001587
};
1601-
} // in every other case, use the attribute node as it is
1602-
// update only the value, set it as node only when/if needed
1603-
else {
1604-
var owner = false;
1605-
var attribute = original.cloneNode(true);
1588+
} // the attribute is special ('value' in input)
1589+
// and it's not SVG *or* the name is exactly data,
1590+
// in this case assign the value directly
1591+
else if (name === 'data' || !isSVG && name in node && !readOnly.test(name)) {
16061592
return function (newValue) {
16071593
if (oldValue !== newValue) {
16081594
oldValue = newValue;
16091595

1610-
if (attribute.value !== newValue) {
1611-
if (newValue == null) {
1612-
if (owner) {
1613-
owner = false;
1614-
node.removeAttributeNode(attribute);
1615-
}
1616-
1617-
attribute.value = newValue;
1618-
} else {
1619-
attribute.value = newValue;
1596+
if (node[name] !== newValue && newValue == null) {
1597+
// cleanup on null to avoid silly IE/Edge bug
1598+
node[name] = '';
1599+
node.removeAttribute(name);
1600+
} else node[name] = newValue;
1601+
}
1602+
};
1603+
} else if (name in Intent.attributes) {
1604+
return function (any) {
1605+
var newValue = Intent.attributes[name](node, any);
16201606

1621-
if (!owner) {
1622-
owner = true;
1623-
node.setAttributeNode(attribute);
1607+
if (oldValue !== newValue) {
1608+
oldValue = newValue;
1609+
if (newValue == null) node.removeAttribute(name);else node.setAttribute(name, newValue);
1610+
}
1611+
};
1612+
} // in every other case, use the attribute node as it is
1613+
// update only the value, set it as node only when/if needed
1614+
else {
1615+
var owner = false;
1616+
var attribute = original.cloneNode(true);
1617+
return function (newValue) {
1618+
if (oldValue !== newValue) {
1619+
oldValue = newValue;
1620+
1621+
if (attribute.value !== newValue) {
1622+
if (newValue == null) {
1623+
if (owner) {
1624+
owner = false;
1625+
node.removeAttributeNode(attribute);
1626+
}
1627+
1628+
attribute.value = newValue;
1629+
} else {
1630+
attribute.value = newValue;
1631+
1632+
if (!owner) {
1633+
owner = true;
1634+
node.setAttributeNode(attribute);
1635+
}
16241636
}
16251637
}
16261638
}
1627-
}
1628-
};
1629-
}
1639+
};
1640+
}
16301641
},
16311642
// in a hyper(node)`<div>${content}</div>` case
16321643
// everything could happen:

min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

umd.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)