virtual-dom
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -1,60 +0,3 @@ | ||
var document = require("global/document") | ||
var createElement = require("./vdom/create-element") | ||
var isVirtualDomNode = require("./lib/is-virtual-dom") | ||
var isVirtualTextNode = require("./lib/is-virtual-text") | ||
var isString = require("./lib/is-string") | ||
var isObject = require("./lib/is-object") | ||
module.exports = render | ||
function render(virtualDom, opts) { | ||
var doc = opts ? opts.document || document : document | ||
var warn = opts ? opts.warn : null | ||
if (virtualDom && typeof virtualDom.init === "function") { | ||
return virtualDom.init() | ||
} else if (isVirtualTextNode(virtualDom)) { | ||
return doc.createTextNode(virtualDom.text) | ||
} else if (isString(virtualDom)) { | ||
return doc.createTextNode(virtualDom) | ||
} else if (!isVirtualDomNode(virtualDom)) { | ||
if (warn) { | ||
warn("Item is not a valid virtual dom node", virtualDom) | ||
} | ||
return null | ||
} | ||
var node = doc.createElement(virtualDom.tagName) | ||
applyProperties(node, virtualDom.properties) | ||
var children = virtualDom.children | ||
for (var i = 0; i < children.length; i++) { | ||
var childNode = render(children[i], opts) | ||
if (childNode) { | ||
node.appendChild(childNode) | ||
} | ||
} | ||
return node | ||
} | ||
function applyProperties(node, props) { | ||
for (var propName in props) { | ||
var propValue = props[propName] | ||
if (typeof propValue === "function") { | ||
propValue(node, propName) | ||
} else if (isObject(propValue)) { | ||
if (!node[propName]) { | ||
node[propName] = {} | ||
} | ||
var nodeValue = node[propName] | ||
for (var k in propValue) { | ||
nodeValue[k] = propValue[k] | ||
} | ||
} else { | ||
node[propName] = propValue | ||
} | ||
} | ||
} | ||
module.exports = createElement |
180
diff.js
@@ -1,181 +0,3 @@ | ||
var createPatch = require("./lib/patch-op") | ||
var diff = require("./vtree/diff") | ||
var isArray = require("./lib/is-array") | ||
var isObject = require("./lib/is-object") | ||
var isVDOMNode = require("./lib/is-virtual-dom") | ||
var isVTextNode = require("./lib/is-virtual-text") | ||
var isWidget = require("./lib/is-widget") | ||
module.exports = diff | ||
function diff(a, b) { | ||
var patch = { a: a } | ||
walk(a, b, patch, 0) | ||
return patch | ||
} | ||
function walk(a, b, patch, index) { | ||
if (a === b) { | ||
return b | ||
} | ||
var apply = patch[index] | ||
if (isWidget(a)) { | ||
// Update a widget | ||
apply = appendPatch(apply, createPatch(a, b)) | ||
} else if (isWidget(b)) { | ||
// Patch in a new widget | ||
apply = appendPatch(apply, createPatch(a, b)) | ||
} else if (isVTextNode(a) && isVTextNode(b)) { | ||
// Update a text node | ||
if (a.text !== b.text) { | ||
apply = appendPatch(apply, createPatch(a.text, b.text)) | ||
} | ||
} else if (isVDOMNode(a) && isVDOMNode(b) && a.tagName === b.tagName) { | ||
// Update a VDOMNode | ||
var propsPatch = diffProps(a.properties, b.properties) | ||
if (propsPatch) { | ||
apply = appendPatch(apply, createPatch(a.properties, propsPatch)) | ||
} | ||
apply = diffChildren(a, b, patch, apply, index) | ||
} else if (a !== b) { | ||
apply = appendPatch(apply, createPatch(a, b)) | ||
// We must detect a remove/replace of widgets here so that | ||
// we can add patch records for any stateful widgets | ||
if (isVDOMNode(a) && a.hasWidgets && | ||
(!isVDOMNode(b) || a.tagName !== b.tagName)) { | ||
destroyWidgets(a, patch, index) | ||
} | ||
} | ||
if (apply) { | ||
patch[index] = apply | ||
} | ||
} | ||
var nullProps = {} | ||
function diffProps(a, b) { | ||
var diff | ||
for (var aKey in a) { | ||
var aValue = a[aKey] | ||
var bValue = b[aKey] || nullProps | ||
if (isObject(aValue)) { | ||
if (getPrototype(bValue) !== getPrototype(aValue)) { | ||
diff = diff || {} | ||
diff[aKey] = bValue | ||
} else { | ||
var objectDiff = diffProps(aValue, bValue || nullProps) | ||
if (objectDiff) { | ||
diff = diff || {} | ||
diff[aKey] = objectDiff | ||
} | ||
} | ||
} else { | ||
if (typeof aValue === "function" || aValue !== bValue) { | ||
diff = diff || {} | ||
diff[aKey] = bValue | ||
} | ||
} | ||
} | ||
for (var bKey in b) { | ||
if (!(bKey in a)) { | ||
diff = diff || {} | ||
diff[bKey] = b[bKey] | ||
} | ||
} | ||
return diff | ||
} | ||
function getPrototype(value) { | ||
if (Object.getPrototypeOf) { | ||
return Object.getPrototypeOf(value) | ||
} else if (value.__proto__) { | ||
return value.__proto__ | ||
} else if (value.constructor) { | ||
return value.constructor.prototype | ||
} | ||
} | ||
function diffChildren(a, b, patch, apply, index) { | ||
var aChildren = a.children | ||
var bChildren = b.children | ||
var aLen = aChildren.length | ||
var bLen = bChildren.length | ||
var len = aLen < bLen ? aLen : bLen | ||
for (var i = 0; i < len; i++) { | ||
var leftNode = aChildren[i] | ||
var rightNode = bChildren[i] | ||
index += 1 | ||
walk(leftNode, rightNode, patch, index) | ||
if (isVDOMNode(leftNode) && leftNode.count) { | ||
index += leftNode.count | ||
} | ||
} | ||
// Excess nodes in a need to be removed | ||
for (; i < aLen; i++) { | ||
var excess = aChildren[i] | ||
index += 1 | ||
patch[index] = createPatch(excess, null) | ||
destroyWidgets(excess, patch, index) | ||
if (isVDOMNode(excess) && excess.count) { | ||
index += excess.count | ||
} | ||
} | ||
// Excess nodes in b need to be added | ||
for (; i < bLen; i++) { | ||
var addition = bChildren[i] | ||
apply = appendPatch(apply, createPatch(null, addition)) | ||
} | ||
return apply | ||
} | ||
// Patch records for all destroyed widgets must be added because we need | ||
// a DOM node reference for the destroy function | ||
function destroyWidgets(vNode, patch, index) { | ||
if (isWidget(vNode)) { | ||
if (typeof vNode.destroy === "function") { | ||
patch[index] = createPatch(vNode, null) | ||
} | ||
} else if (isVDOMNode(vNode) && vNode.hasWidgets) { | ||
var children = vNode.children | ||
var len = children.length | ||
for (var i = 0; i < len; i++) { | ||
var child = children[i] | ||
index += 1 | ||
destroyWidgets(child, patch, index) | ||
if (isVDOMNode(child) && child.count) { | ||
index += child.count | ||
} | ||
} | ||
} | ||
} | ||
function appendPatch(apply, patch) { | ||
if (apply) { | ||
if (isArray(apply)) { | ||
apply.push(patch) | ||
} else { | ||
apply = [apply, patch] | ||
} | ||
return apply | ||
} else { | ||
return patch | ||
} | ||
} |
56
h.js
@@ -1,57 +0,3 @@ | ||
var extend = require("extend") | ||
var h = require("./h/") | ||
var isArray = require("./lib/is-array") | ||
var isString = require("./lib/is-string") | ||
var parseTag = require("./lib/parse-tag") | ||
var isVirtualDOMNode = require("./lib/is-virtual-dom") | ||
var isVirtualTextNode = require("./lib/is-virtual-text") | ||
var VirtualDOMNode = require("./virtual-dom-node.js") | ||
var VirtualTextNode = require("./virtual-text-node.js") | ||
module.exports = h | ||
function h(tagName, properties, children) { | ||
var childNodes = [] | ||
var tag, props | ||
if (!children) { | ||
if (isChildren(properties)) { | ||
children = properties | ||
props = {} | ||
} | ||
} | ||
props = props || extend({}, properties) | ||
tag = parseTag(tagName, props) | ||
if (children != null) { | ||
if (isArray(children)) { | ||
for (var i = 0; i < children.length; i++) { | ||
addChild(children[i], childNodes) | ||
} | ||
} else { | ||
addChild(children, childNodes) | ||
} | ||
} | ||
return new VirtualDOMNode(tag, props, childNodes) | ||
} | ||
function addChild(c, childNodes) { | ||
if (isString(c)) { | ||
childNodes.push(new VirtualTextNode(c)) | ||
} else { | ||
// For now, we push all objects regardless of type | ||
childNodes.push(c) | ||
} | ||
} | ||
function isChild(x) { | ||
return isVirtualDOMNode(x) || isVirtualTextNode(x) | ||
} | ||
function isChildren(x) { | ||
return isChild(x) || isArray(x) || isString(x) | ||
} |
{ | ||
"name": "virtual-dom", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "A batched diff-based DOM rendering strategy", | ||
@@ -24,3 +24,6 @@ "keywords": [], | ||
"global": "^3.0.0", | ||
"semver": "~2.2.1" | ||
"semver": "~2.2.1", | ||
"x-is-array": "^0.1.0", | ||
"x-is-object": "^0.1.0", | ||
"x-is-string": "^0.1.0" | ||
}, | ||
@@ -27,0 +30,0 @@ "devDependencies": { |
71
patch.js
@@ -1,72 +0,3 @@ | ||
var document = require("global/document") | ||
var patch = require("./vdom/patch") | ||
var domIndex = require("./lib/dom-index") | ||
var isArray = require("./lib/is-array") | ||
module.exports = patch | ||
function patch(rootNode, patches) { | ||
var indices = patchIndices(patches) | ||
if (indices.length === 0) { | ||
return rootNode | ||
} | ||
var index = domIndex(rootNode, patches.a, indices) | ||
var ownerDocument = rootNode.ownerDocument | ||
var renderOptions | ||
if (ownerDocument !== document) { | ||
renderOptions = { | ||
document: ownerDocument | ||
} | ||
} | ||
for (var i = 0; i < indices.length; i++) { | ||
var nodeIndex = indices[i] | ||
rootNode = applyPatch(rootNode, | ||
index[nodeIndex], | ||
patches[nodeIndex], | ||
renderOptions) | ||
} | ||
return rootNode | ||
} | ||
function applyPatch(rootNode, domNode, patchList, renderOptions) { | ||
if (!domNode) { | ||
return rootNode | ||
} | ||
var newNode | ||
if (isArray(patchList)) { | ||
for (var i = 0; i < patchList.length; i++) { | ||
newNode = patchList[i].apply(domNode, renderOptions) | ||
if (domNode === rootNode) { | ||
rootNode = newNode | ||
} | ||
} | ||
} else { | ||
newNode = patchList.apply(domNode, renderOptions) | ||
if (domNode === rootNode) { | ||
rootNode = newNode | ||
} | ||
} | ||
return rootNode | ||
} | ||
function patchIndices(patches) { | ||
var indices = [] | ||
for (var key in patches) { | ||
if (key !== "a") { | ||
indices.push(Number(key)) | ||
} | ||
} | ||
return indices | ||
} |
@@ -6,8 +6,8 @@ var test = require("tape") | ||
var patch = require("../patch") | ||
var Node = require("../virtual-dom-node") | ||
var render = require("../create-element") | ||
var version = require("../version") | ||
var Node = require("../vtree/vnode") | ||
var render = require("../vdom/create-element") | ||
var version = require("../vtree/version") | ||
// VirtualDOMNode tests | ||
// VirtualNode tests | ||
test("Node is a function", function (assert) { | ||
@@ -19,3 +19,3 @@ assert.equal(typeof Node, "function") | ||
test("Node type and version are set", function (assert) { | ||
assert.equal(Node.prototype.type, "VirtualDOMNode") | ||
assert.equal(Node.prototype.type, "VirtualNode") | ||
assert.deepEqual(Node.prototype.version, version.split(".")) | ||
@@ -128,3 +128,3 @@ assert.end() | ||
assert.true(node instanceof Node, "node is a VirtualDOMNode") | ||
assert.true(node instanceof Node, "node is a VirtualNode") | ||
assert.equal(node.tagName, tagName, "tag names are equal") | ||
@@ -305,5 +305,7 @@ assert.deepEqual(node.properties, properties, "propeties are equal") | ||
} | ||
}, [ | ||
}) | ||
vdom.children = [ | ||
badObject, null | ||
]) | ||
] | ||
@@ -511,2 +513,5 @@ var i = 0 | ||
return testNode | ||
}, | ||
update: function () { | ||
initCount = 1000000 | ||
} | ||
@@ -529,2 +534,5 @@ } | ||
return testNode | ||
}, | ||
update: function () { | ||
initCount = 1000000 | ||
} | ||
@@ -531,0 +539,0 @@ } |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
25
56446
8
+ Addedx-is-array@^0.1.0
+ Addedx-is-object@^0.1.0
+ Addedx-is-string@^0.1.0
+ Addedx-is-array@0.1.0(transitive)
+ Addedx-is-object@0.1.0(transitive)
+ Addedx-is-string@0.1.0(transitive)