Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
backport spatialized code
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxenko committed Jan 28, 2017
1 parent be8bf7a commit 008d16e
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 58 deletions.
67 changes: 41 additions & 26 deletions lib/diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* Diff
*/

var PATCH_CREATE = 0;
var PATCH_REMOVE = 1;
var PATCH_CREATE = 0;
var PATCH_REMOVE = 1;
var PATCH_REPLACE = 2;
var PATCH_REORDER = 3;
var PATCH_PROPS = 4;
var PATCH_PROPS = 4;

/**
* Diff two virtual dom trees
Expand All @@ -17,9 +17,8 @@ var PATCH_PROPS = 4;
* @param {Object} oldNode virtual tree to compare
* @param {Object} newNode virtual tree to compare with
*/
var diff = function(oldNode, newNode) {

if (typeof oldNode === 'undefined' ||typeof newNode === 'undefined') {
var diff = function (oldNode, newNode) {
if (typeof oldNode === 'undefined' || typeof newNode === 'undefined') {
throw new Error('cannot diff undefined nodes');
}

Expand All @@ -40,19 +39,22 @@ var diff = function(oldNode, newNode) {
* @param {} b
* @param {} patches
*/
var _diffTree = function(a, b, patches) {

var _diffTree = function (a, b, patches) {
_diffProps(a, b, patches);

if (b.tag === 'text') {
if (b.children !== a.children) {
patches.push({ t : PATCH_REPLACE, node : a, with : b });
patches.push({ t: PATCH_REPLACE, node: a, with: b });
}
return;
}

if (Array.isArray(b.children)) {
_diffChild(a.children, b.children, a, patches);
_diffChild(a.children, b.children, a, patches);
} else if (Array.isArray(a.children)) {
for (var i = 0; i < a.children.length; i++) {
patches.push({ t: PATCH_REMOVE, from: i, node: _nodeId(a), item: _nodeId(a.children[i]) });
}
}

return patches;
Expand All @@ -69,16 +71,28 @@ var _diffTree = function(a, b, patches) {
* @param {} pn
* @param {} patches
*/
var _diffChild = function(a, b, pn, patches) {
var reorderMap = [], i, j, found;
var _diffChild = function (a, b, pn, patches) {
var reorderMap = [];
var i;
var j;
var found;

for (i = 0; i < b.length; i++) {
found = false;

if (!a) {
if (!pn.children) {
pn.children = [];
}

patches.push({ t: PATCH_CREATE, to: i, node: _nodeId(pn), item: _nodeId(b[i].clone()) });
continue;
}

for (j = 0; j < a.length; j++) {
if (_isNodeSame(a[j], b[i]) && reorderMap.indexOf(a[j]) === -1) {
if (j !== i) {
patches.push({ t : PATCH_REORDER, from : j, to : i, node : _nodeId(pn), item : _nodeId(a[j])});
patches.push({ t: PATCH_REORDER, from: j, to: i, node: _nodeId(pn), item: _nodeId(a[j]) });
}
reorderMap.push(a[j]);

Expand All @@ -90,14 +104,15 @@ var _diffChild = function(a, b, pn, patches) {

if (found === false) {
reorderMap.push(null);
patches.push({ t : PATCH_CREATE, to : i, node : _nodeId(pn), item :
b[i].tag === 'text' ? _nodeId(b[i]) :_nodeId(b[i].clone())});
patches.push({ t: PATCH_CREATE, to: i, node: _nodeId(pn), item: b[i].tag === 'text' ? _nodeId(b[i]) : _nodeId(b[i].clone()) });
}
}

if (!a) return;

for (i = 0; i < a.length; i++) {
if (reorderMap.indexOf(a[i]) === -1) {
patches.push({ t: PATCH_REMOVE, from : i, node : _nodeId(pn), item : _nodeId(a[i])});
patches.push({ t: PATCH_REMOVE, from: i, node: _nodeId(pn), item: _nodeId(a[i]) });
}
}
};
Expand All @@ -113,7 +128,7 @@ var _diffChild = function(a, b, pn, patches) {
* @param {} patches
* @param {} type
*/
var _diffProps = function(a, b, patches) {
var _diffProps = function (a, b, patches) {
if (!a || !b || !a.props && !b.props) {
return;
}
Expand All @@ -127,23 +142,23 @@ var _diffProps = function(a, b, patches) {
for (i = 0; i < battrs.length || i < aattrs.length; i++) {
if (i < battrs.length) {
if (!(battrs[i] in a.props) || b.props[battrs[i]] !== a.props[battrs[i]]) {
toChange.push({ name : battrs[i], value : b.props[battrs[i]] });
toChange.push({ name: battrs[i], value: b.props[battrs[i]] });
}
}

if (i < aattrs.length) {
if (!(aattrs[i] in b.props)) {
toRemove.push({ name : aattrs[i] });
toRemove.push({ name: aattrs[i] });
}
}
}

if (toRemove.length > 0) {
patches.push({ t : PATCH_PROPS, remove : toRemove, node : _nodeId(a) });
patches.push({ t: PATCH_PROPS, remove: toRemove, node: _nodeId(a) });
}

if (toChange.length > 0) {
patches.push({ t : PATCH_PROPS, change : toChange, node : _nodeId(a) });
patches.push({ t: PATCH_PROPS, change: toChange, node: _nodeId(a) });
}
};

Expand All @@ -155,7 +170,7 @@ var _diffProps = function(a, b, patches) {
* @access private
* @param {} node
*/
var _nodeId = function(node) {
var _nodeId = function (node) {
return node;
};

Expand All @@ -168,13 +183,13 @@ var _nodeId = function(node) {
* @param {} a
* @param {} b
*/
var _isNodeSame = function(a, b) {
var _isNodeSame = function (a, b) {
return a.tag === b.tag;
};

exports.PATCH_CREATE = PATCH_CREATE;
exports.PATCH_REMOVE = PATCH_REMOVE;
exports.PATCH_CREATE = PATCH_CREATE;
exports.PATCH_REMOVE = PATCH_REMOVE;
exports.PATCH_REPLACE = PATCH_REPLACE;
exports.PATCH_REORDER = PATCH_REORDER;
exports.PATCH_PROPS = PATCH_PROPS;
exports.PATCH_PROPS = PATCH_PROPS;
exports.diff = diff;
69 changes: 38 additions & 31 deletions lib/h.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
* @function
* @access public
*/
var h = function(argv) {
if (!(this instanceof h)) {
return new h(arguments);
var H = function (argv) {
if (!(this instanceof H)) {
if (typeof argv === 'function') {
return argv.apply(argv, [].slice.call(arguments, 1, arguments.length));
}
return new H(arguments);
}

if (argv[0] instanceof h) {
if (argv[0] instanceof H) {
return argv[0];
}

Expand All @@ -34,11 +37,11 @@ var h = function(argv) {
this.children = argv[2];
} else {
this.children = [].concat.apply([], [].slice.call(argv, 2, argv.length))
.filter(function(n) {
return n !== null && n !== undefined;
.filter(function (n) {
return n !== null && n !== undefined && n !== false;
})
.map(function(n) {
if (!(n instanceof h)) {
.map(function (n) {
if (!(n instanceof H)) {
return _createTextNode(n);
} else {
return n;
Expand All @@ -56,7 +59,7 @@ var h = function(argv) {
* @access public
* @param {Boolean} fasle - do not save DOM into tree
*/
h.prototype.render = function(node, parent) {
H.prototype.render = function (node, parent) {
node = node || this;

node.el = createElement(node.tag ? node : this, parent);
Expand All @@ -72,7 +75,7 @@ h.prototype.render = function(node, parent) {
return node.el;
};

h.prototype.setProp = function(name, value) {
H.prototype.setProp = function (name, value) {
if (typeof this.el !== 'undefined') {
if (name === 'className') {
this.el.setAttribute('class', value);
Expand All @@ -95,7 +98,7 @@ h.prototype.setProp = function(name, value) {
this.props[name] = value;
};

h.prototype.setProps = function(props) {
H.prototype.setProps = function (props) {
var propNames = Object.keys(props);

for (var i = 0; i < propNames.length; i++) {
Expand All @@ -104,7 +107,7 @@ h.prototype.setProps = function(props) {
}
};

h.prototype.rmProp = function(name) {
H.prototype.rmProp = function (name) {
if (typeof this.el !== 'undefined') {
if (name === 'className') {
this.el.removeAttribute('class');
Expand All @@ -123,7 +126,7 @@ h.prototype.rmProp = function(name) {
delete this.props[name];
};

h.prototype.addEvent = function(name, listener) {
H.prototype.addEvent = function (name, listener) {
name = name.slice(2).toLowerCase();

this.listeners = this.listeners || {};
Expand All @@ -136,35 +139,39 @@ h.prototype.addEvent = function(name, listener) {
this.el.addEventListener(name, listener);
};

h.prototype.removeEvent = function(name) {
H.prototype.removeEvent = function (name) {
if (name in this.listeners) {
this.el.removeEventListener(name, this.listeners[name]);
delete this.listeners[name];
}
};

h.prototype.clone = function() {
H.prototype.clone = function () {
var node = {
tag : String(this.tag),
props : _cloneProps(this.props)
tag: String(this.tag),
props: _cloneProps(this.props)
};

if (typeof this.children !== 'undefined') {
node.children = this.tag === 'text' ? String(this.children) :
this.children.map(function(child) {
node.children = this.tag === 'text'
? String(this.children)
: this.children.map(function (child) {
return child.tag === 'text' ? _createTextNode(child.children) : child.clone();
});
}

return h(node.tag, node.props, node.children);
return H(node.tag, node.props, node.children);
};

var _cloneProps = function(props, keepRefs) {
var _cloneProps = function (props, keepRefs) {
if (typeof keepRefs === 'undefined') {
keepRefs = true;
}

var attrs = Object.keys(props), i, name, cloned = {};
var attrs = Object.keys(props);
var i;
var name;
var cloned = {};

for (i = 0; i < attrs.length; i++) {
name = attrs[i];
Expand All @@ -183,7 +190,7 @@ var _cloneProps = function(props, keepRefs) {
return cloned;
};

var _stylePropToString = function(props) {
var _stylePropToString = function (props) {
var out = '';
var attrs = Object.keys(props);

Expand All @@ -197,17 +204,17 @@ var _stylePropToString = function(props) {
return out;
};

var _createTextNode = function(text) {
var _createTextNode = function (text) {
return {
tag : 'text',
children : String(text)
tag: 'text',
children: String(text)
};
};

var createElement = function(node, parent) {
node.el = node.tag === 'text' ?
document.createTextNode(node.children) :
document.createElement(node.tag);
var createElement = function (node, parent) {
node.el = node.tag === 'text'
? document.createTextNode(node.children)
: document.createElement(node.tag);

if (typeof node.props !== 'undefined') {
node.setProps(node.props);
Expand All @@ -220,5 +227,5 @@ var createElement = function(node, parent) {
return node.el;
};

exports.h = h;
exports.h = H;
exports.createElement = createElement;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "basic-virtual-dom",
"version": "0.1.6",
"version": "0.2.0",
"description": "Basic virtual dom implementation",
"main": "index.js",
"files": [
Expand Down

0 comments on commit 008d16e

Please sign in to comment.