Skip to content

Commit

Permalink
Added direct attributes access via . notation
Browse files Browse the repository at this point in the history
As this feature has been proven to be worth it in various
occasions with _lighterhtml_, and since it's super trivial
to implement, I've decided to offer the same feature in hyperHTML.
  • Loading branch information
WebReflection committed Feb 20, 2020
1 parent 0a11145 commit c6fbcb8
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 85 deletions.
16 changes: 16 additions & 0 deletions cjs/objects/Updates.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ const asNode = (item, i) => {
// returns true if domdiff can handle the value
const canDiff = value => 'ELEMENT_NODE' in value;

const hyperSetter = (node, name, svg) => svg ?
value => {
try {
node[name] = value;
}
catch (nope) {
node.setAttribute(name, value);
}
} :
value => {
node[name] = value;
};

// when a Promise is used as interpolation value
// its result must be parsed once resolved.
// This callback is in charge of understanding what to do
Expand Down Expand Up @@ -99,6 +112,9 @@ Tagger.prototype = {
// 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)) {
Expand Down
16 changes: 8 additions & 8 deletions esm.js

Large diffs are not rendered by default.

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

const hyperSetter = (node, name, svg) => svg ?
value => {
try {
node[name] = value;
}
catch (nope) {
node.setAttribute(name, value);
}
} :
value => {
node[name] = value;
};

// when a Promise is used as interpolation value
// its result must be parsed once resolved.
// This callback is in charge of understanding what to do
Expand Down Expand Up @@ -99,6 +112,9 @@ Tagger.prototype = {
// 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)) {
Expand Down
125 changes: 69 additions & 56 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1470,6 +1470,18 @@ var hyperHTML = (function (document) {

var canDiff = function canDiff(value) {
return 'ELEMENT_NODE' in value;
};

var hyperSetter = function hyperSetter(node, name, svg) {
return svg ? function (value) {
try {
node[name] = value;
} catch (nope) {
node.setAttribute(name, value);
}
} : function (value) {
node[name] = value;
};
}; // when a Promise is used as interpolation value
// its result must be parsed once resolved.
// This callback is in charge of understanding what to do
Expand Down Expand Up @@ -1522,77 +1534,78 @@ var hyperHTML = (function (document) {
var oldValue; // if the attribute is the style one
// handle it differently from others

if (name === 'style') return hyperStyle(node, original, 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();
}
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);

return function (newValue) {
if (oldValue !== newValue) {
if (oldValue) node.removeEventListener(type, oldValue, false);
oldValue = newValue;
if (newValue) node.addEventListener(type, newValue, false);
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
Loading

0 comments on commit c6fbcb8

Please sign in to comment.