virtual-dom
Advanced tools
Comparing version 0.0.5 to 0.0.6
@@ -15,3 +15,3 @@ var isArray = require("x-is-array") | ||
function h(tagName, properties, children) { | ||
var tag, props, childNodes | ||
var tag, props, childNodes, key | ||
@@ -51,3 +51,8 @@ if (!children) { | ||
return new VNode(tag, props, childNodes) | ||
if (props && "key" in props) { | ||
key = props.key | ||
delete props.key | ||
} | ||
return new VNode(tag, props, childNodes, key) | ||
} | ||
@@ -54,0 +59,0 @@ |
{ | ||
"name": "virtual-dom", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "A batched diff-based DOM rendering strategy", | ||
@@ -22,5 +22,5 @@ "keywords": [], | ||
"global": "^3.0.1", | ||
"is-object": "^0.1.2", | ||
"x-is-array": "^0.1.0", | ||
"x-is-string": "^0.1.0", | ||
"is-object": "^0.1.2" | ||
"x-is-string": "^0.1.0" | ||
}, | ||
@@ -27,0 +27,0 @@ "devDependencies": { |
@@ -33,10 +33,10 @@ var test = require("tape") | ||
"value": "not a hook" | ||
}, [], null, null) | ||
}, [], undefined, undefined) | ||
var parentNode = new Node("div", { | ||
"id": "not a hook" | ||
}, [node], null, null) | ||
}, [node], undefined, undefined) | ||
assert.equal(node.hooks.id, propValue) | ||
assert.equal(parentNode.hooks, null) | ||
assert.equal(parentNode.hooks, undefined) | ||
assert.ok(parentNode.descendantHooks) | ||
@@ -81,3 +81,3 @@ assert.end() | ||
test("hook get called in patch", function (assert) { | ||
test("hooks get called in patch", function (assert) { | ||
var counter = 0 | ||
@@ -84,0 +84,0 @@ var prev = h("div") |
@@ -16,2 +16,3 @@ var test = require("tape") | ||
require("./undefined-properties.js") | ||
require("./keys.js") | ||
@@ -92,3 +93,2 @@ // VirtualNode tests | ||
test("second argument can be children", function (assert) { | ||
debugger | ||
var node1 = h("#important.pretty", "test") | ||
@@ -176,3 +176,2 @@ var node2 = h("#important.pretty", ["test"]) | ||
test("node id is applied correctly", function (assert) { | ||
debugger | ||
var vdom = h("#important") | ||
@@ -179,0 +178,0 @@ var dom = render(vdom) |
@@ -115,2 +115,12 @@ var test = require("tape") | ||
test("create object on node for nested properties", function (assert) { | ||
var prev = h("div", { propA: null }) | ||
var curr = h("div", { propA: { nested: true } }) | ||
var elem = createAndPatch(prev, curr) | ||
assert.equal(elem.propA.nested, true) | ||
assert.end() | ||
}) | ||
function createAndPatch(prev, curr) { | ||
@@ -117,0 +127,0 @@ var elem = render(prev) |
@@ -17,3 +17,3 @@ var isObject = require("is-object") | ||
if (isObject(propValue)) { | ||
if (typeof node[propName] !== "object") { | ||
if (!isObject(node[propName])) { | ||
node[propName] = {} | ||
@@ -25,3 +25,3 @@ } | ||
} | ||
} else { | ||
} else if (propValue !== undefined) { | ||
node[propName] = propValue | ||
@@ -28,0 +28,0 @@ } |
@@ -1,7 +0,5 @@ | ||
var isString = require("x-is-string") | ||
var applyProperties = require("./apply-properties") | ||
var isWidget = require("../vtree/is-widget") | ||
var isVNode = require("../vtree/is-vnode") | ||
var VPatch = require("../vtree/vpatch") | ||
@@ -14,18 +12,25 @@ var render = require("./create-element") | ||
function applyPatch(vpatch, domNode, renderOptions) { | ||
var type = vpatch.type | ||
var vNode = vpatch.vNode | ||
var patch = vpatch.patch | ||
if (patch == null) { | ||
return removeNode(domNode, vNode) | ||
} else if (vNode == null) { | ||
return insertNode(domNode, patch, renderOptions) | ||
} else if (isString(patch)) { | ||
return stringPatch(domNode, vNode, patch, renderOptions) | ||
} else if (isWidget(patch)) { | ||
return widgetPatch(domNode, vNode, patch, renderOptions) | ||
} else if (isVNode(patch)) { | ||
return vNodePatch(domNode, vNode, patch, renderOptions) | ||
} else { | ||
applyProperties(domNode, patch, vNode.propeties) | ||
return domNode | ||
switch (type) { | ||
case VPatch.REMOVE: | ||
return removeNode(domNode, vNode) | ||
case VPatch.INSERT: | ||
return insertNode(domNode, patch, renderOptions) | ||
case VPatch.VTEXT: | ||
return stringPatch(domNode, vNode, patch, renderOptions) | ||
case VPatch.WIDGET: | ||
return widgetPatch(domNode, vNode, patch, renderOptions) | ||
case VPatch.VNODE: | ||
return vNodePatch(domNode, vNode, patch, renderOptions) | ||
case VPatch.ORDER: | ||
reorderChildren(domNode, patch) | ||
return domNode | ||
case VPatch.PROPS: | ||
applyProperties(domNode, patch, vNode.propeties) | ||
return domNode | ||
default: | ||
return domNode | ||
} | ||
@@ -56,13 +61,15 @@ } | ||
function stringPatch(domNode, leftVNode, newString, renderOptions) { | ||
function stringPatch(domNode, leftVNode, vText, renderOptions) { | ||
var newNode | ||
if (domNode.nodeType === 3) { | ||
domNode.replaceData(0, domNode.length, newString) | ||
return domNode | ||
} | ||
domNode.replaceData(0, domNode.length, vText.text) | ||
newNode = domNode | ||
} else { | ||
var parentNode = domNode.parentNode | ||
newNode = render(vText, renderOptions) | ||
var parentNode = domNode.parentNode | ||
var newNode = render(newString, renderOptions) | ||
if (parentNode) { | ||
parentNode.replaceChild(newNode, domNode) | ||
if (parentNode) { | ||
parentNode.replaceChild(newNode, domNode) | ||
} | ||
} | ||
@@ -75,12 +82,9 @@ | ||
function widgetPatch(domNode, leftVNode, widgetUpdate, renderOptions) { | ||
if (isWidget(leftVNode)) { | ||
if (updateWidget(leftVNode, widgetUpdate)) { | ||
var updatedNode = widgetUpdate.update(leftVNode, domNode) | ||
return updatedNode || domNode | ||
} | ||
function widgetPatch(domNode, leftVNode, widget, renderOptions) { | ||
if (updateWidget(leftVNode, widget)) { | ||
return widget.update(leftVNode, domNode) || domNode | ||
} | ||
var parentNode = domNode.parentNode | ||
var newWidget = render(widgetUpdate, renderOptions) | ||
var newWidget = render(widget, renderOptions) | ||
@@ -96,5 +100,5 @@ if (parentNode) { | ||
function vNodePatch(domNode, leftVNode, rightVNode, renderOptions) { | ||
function vNodePatch(domNode, leftVNode, vNode, renderOptions) { | ||
var parentNode = domNode.parentNode | ||
var newNode = render(rightVNode, renderOptions) | ||
var newNode = render(vNode, renderOptions) | ||
@@ -115,1 +119,21 @@ if (parentNode) { | ||
} | ||
function reorderChildren(domNode, bIndex) { | ||
var children = [] | ||
var childNodes = domNode.childNodes | ||
var len = childNodes.length | ||
var i | ||
for (i = 0; i < len; i++) { | ||
children.push(domNode.childNodes[i]) | ||
} | ||
for (i = 0; i < len; i++) { | ||
var move = bIndex[i] | ||
if (move !== undefined) { | ||
var node = children[move] | ||
domNode.removeChild(node) | ||
domNode.insertBefore(node, childNodes[i]) | ||
} | ||
} | ||
} |
@@ -25,31 +25,38 @@ var isArray = require("x-is-array") | ||
if (isWidget(a) || isWidget(b)) { | ||
// Update/patch a widget | ||
apply = appendPatch(apply, new VPatch(a, b)) | ||
} else if (isVText(a) && isVText(b)) { | ||
// Update a text node | ||
if (a.text !== b.text) { | ||
apply = appendPatch(apply, new VPatch(a.text, b.text)) | ||
if (isWidget(b)) { | ||
apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b)) | ||
if (!isWidget(a)) { | ||
destroyWidgets(a, patch, index) | ||
} | ||
} else if (isVNode(a) && isVNode(b) && | ||
a.tagName === b.tagName && | ||
a.namespace === b.namespace) { | ||
// Update a VDOMNode | ||
var propsPatch = diffProps(a.properties, b.properties, b.hooks) | ||
if (propsPatch) { | ||
apply = appendPatch(apply, new VPatch(a.properties, propsPatch)) | ||
} else if (isVText(b)) { | ||
if (!isVText(a)) { | ||
apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) | ||
destroyWidgets(a, patch, index) | ||
} else if (a.text !== b.text) { | ||
apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) | ||
} | ||
} else if (isVNode(b)) { | ||
if (isVNode(a)) { | ||
if (a.tagName === b.tagName && | ||
a.namespace === b.namespace && | ||
a.key === b.key) { | ||
var propsPatch = diffProps(a.properties, b.properties, b.hooks) | ||
if (propsPatch) { | ||
apply = appendPatch(apply, | ||
new VPatch(VPatch.PROPS, a, propsPatch)) | ||
} | ||
} else { | ||
apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) | ||
destroyWidgets(a, patch, index) | ||
} | ||
apply = diffChildren(a, b, patch, apply, index) | ||
} else if (a !== b) { | ||
apply = appendPatch(apply, new VPatch(a, b)) | ||
// We must detect a remove/replace of widgets here so that | ||
// we can add patch records for any stateful widgets | ||
if (isVNode(a) && a.hasWidgets && | ||
(!isVNode(b) || | ||
a.tagName !== b.tagName || | ||
a.namespace !== b.namespace)) { | ||
apply = diffChildren(a, b, patch, apply, index) | ||
} else { | ||
apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) | ||
destroyWidgets(a, patch, index) | ||
} | ||
} else if (b == null) { | ||
apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b)) | ||
destroyWidgets(a, patch, index) | ||
} | ||
@@ -120,4 +127,6 @@ | ||
var bLen = bChildren.length | ||
var len = aLen < bLen ? aLen : bLen | ||
var len = aLen > bLen ? aLen : bLen | ||
aChildren = reorder(aChildren, bChildren, len) | ||
for (var i = 0; i < len; i++) { | ||
@@ -127,4 +136,18 @@ var leftNode = aChildren[i] | ||
index += 1 | ||
walk(leftNode, rightNode, patch, index) | ||
if (!leftNode) { | ||
if (rightNode) { | ||
// Excess nodes in b need to be added | ||
apply = appendPatch(apply, new VPatch(VPatch.INSERT, null, rightNode)) | ||
} | ||
} else if (!rightNode) { | ||
if (leftNode) { | ||
// Excess nodes in a need to be removed | ||
patch[index] = new VPatch(VPatch.REMOVE, leftNode, null) | ||
destroyWidgets(leftNode, patch, index) | ||
} | ||
} else { | ||
walk(leftNode, rightNode, patch, index) | ||
} | ||
if (isVNode(leftNode) && leftNode.count) { | ||
@@ -135,20 +158,7 @@ index += leftNode.count | ||
// Excess nodes in a need to be removed | ||
for (; i < aLen; i++) { | ||
var excess = aChildren[i] | ||
index += 1 | ||
patch[index] = new VPatch(excess, null) | ||
destroyWidgets(excess, patch, index) | ||
if (isVNode(excess) && excess.count) { | ||
index += excess.count | ||
} | ||
if (aChildren.moves) { | ||
// Reorder nodes last | ||
apply = appendPatch(apply, new VPatch(VPatch.ORDER, a, aChildren.moves)) | ||
} | ||
// Excess nodes in b need to be added | ||
for (; i < bLen; i++) { | ||
var addition = bChildren[i] | ||
apply = appendPatch(apply, new VPatch(null, addition)) | ||
} | ||
return apply | ||
@@ -162,3 +172,3 @@ } | ||
if (typeof vNode.destroy === "function") { | ||
patch[index] = new VPatch(vNode, null) | ||
patch[index] = new VPatch(VPatch.REMOVE, vNode, null) | ||
} | ||
@@ -185,3 +195,3 @@ } else if (isVNode(vNode) && vNode.hasWidgets) { | ||
if (vNode.hooks) { | ||
patch[index] = new VPatch(vNode.hooks, vNode.hooks) | ||
patch[index] = new VPatch(VPatch.PROPS, vNode.hooks, vNode.hooks) | ||
} | ||
@@ -206,2 +216,71 @@ | ||
// List diff, naive left to right reordering | ||
function reorder(aChildren, bChildren, len) { | ||
var aKeys = keyIndex(aChildren) | ||
if (!aKeys) { | ||
return aChildren | ||
} | ||
var bKeys = keyIndex(bChildren) | ||
if (!bKeys) { | ||
return aChildren | ||
} | ||
var aMatch, bMatch | ||
for (var key in aKeys) { | ||
if (key in bKeys) { | ||
if (!aMatch) { | ||
aMatch = {} | ||
bMatch = {} | ||
} | ||
var aIndex = aKeys[key] | ||
var bIndex = bKeys[key] | ||
aMatch[aIndex] = bIndex | ||
bMatch[bIndex] = aIndex | ||
} | ||
} | ||
if (!aMatch) { | ||
return bChildren | ||
} | ||
var shuffle = [] | ||
var freeIndex = 0 | ||
shuffle.moves = bMatch | ||
for (var i = 0; i < len; i++) { | ||
var move = bMatch[i] | ||
if (move !== undefined) { | ||
shuffle[i] = aChildren[move] | ||
} else { | ||
while (freeIndex in aMatch) { | ||
freeIndex++ | ||
} | ||
shuffle[i] = aChildren[freeIndex++] | ||
} | ||
} | ||
return shuffle | ||
} | ||
function keyIndex(children) { | ||
var i, keys | ||
for (i = 0; i < children.length; i++) { | ||
var child = children[i] | ||
if (child.key !== undefined) { | ||
keys = keys || {} | ||
keys[child.key] = i | ||
} | ||
} | ||
return keys | ||
} | ||
function appendPatch(apply, patch) { | ||
@@ -208,0 +287,0 @@ if (apply) { |
@@ -1,1 +0,1 @@ | ||
module.exports = "1" | ||
module.exports = "1" |
@@ -15,3 +15,3 @@ var version = require("./version") | ||
this.children = children || noChildren | ||
this.key = (typeof key === "string") ? key : null | ||
this.key = key != null ? String(key) : undefined | ||
this.namespace = (typeof namespace === "string") ? namespace : null | ||
@@ -22,4 +22,4 @@ | ||
var hasWidgets = false | ||
var hooks = null | ||
var descendantHooks = false | ||
var hooks | ||
@@ -26,0 +26,0 @@ for (var propName in properties) { |
var version = require("./version") | ||
VirtualPatch.NONE = 0 | ||
VirtualPatch.VTEXT = 1 | ||
VirtualPatch.VNODE = 2 | ||
VirtualPatch.WIDGET = 3 | ||
VirtualPatch.PROPS = 4 | ||
VirtualPatch.ORDER = 5 | ||
VirtualPatch.INSERT = 6 | ||
VirtualPatch.REMOVE = 7 | ||
module.exports = VirtualPatch | ||
function VirtualPatch(vNode, patch) { | ||
function VirtualPatch(type, vNode, patch) { | ||
this.type = Number(type) | ||
this.vNode = vNode | ||
@@ -7,0 +17,0 @@ this.patch = patch |
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
77208
32
2058