Simple Incremental DOM
by Alexey Zuev
HTML
<input type="text" value="Alexey">
<button>Increment</button>
CSS
body {
padding: 20px;
font-family: Helvetica;
}
JavaScript
const NODE_DATA_KEY = '__ID_Data__';
// The current nodes being processed
let currentNode = null;
let currentParent = null;
class NodeData {
// key
// attrs
constructor(name) {
this.name = name;
this.text = null;
}
}
function getData(node) {
if (!node[NODE_DATA_KEY]) {
node[NODE_DATA_KEY] = new NodeData(node.nodeName.toLowerCase());
}
return node[NODE_DATA_KEY];
}
function enterNode() {
currentParent = currentNode;
currentNode = null;
}
function nextNode() {
currentNode = currentNode ? currentNode.nextSibling : currentParent.firstChild;
}
function exitNode() {
currentNode = currentParent;
currentParent = currentParent.parentNode;
}
const matches = function(matchNode, name/*, key */) {
const data = getData(matchNode);
return name === data.name // && key === data.key;
};
function renderDOM(name) {
if (currentNode && matches(currentNode, name/*, key */)) {
return currentNode;
}
const node = name === '#text' ?
document.createTextNode('') :
document.createElement(name);
currentParent.insertBefore(node, currentNode);
currentNode = node;
return node;
}
function elementOpen(name) {
nextNode();
const node = renderDOM(name);
enterNode();
// check for updates, i.t attributes
const data = getData(node);
return currentParent;
}
function elementClose(node) {
exitNode();
return currentNode;
}
function text(value) {
nextNode();
const node = renderDOM('#text');
// checks for text updates
const data = getData(node);
if (data.text !== value) {
data.text = (value);
node.data = value;
}
return currentNode;
}
function patch(node, fn, data) {
currentNode = node;
enterNode();
fn(data);
exitNode();
};
function render(data) {
elementOpen('h1');
{
text('Hello, ' + data.user)
}
elementClose('h1');
elementOpen('ul')
{
elementOpen('li');
{
text('Counter: ')
elementOpen('span');
{
text(data.counter);
...