fix node index displacement by null/undefined nodes

This commit is contained in:
Leo Horie 2014-04-20 21:48:33 -04:00
parent f589a33842
commit a425bbca88
10 changed files with 56 additions and 20 deletions

View file

@ -69,6 +69,11 @@
<li>m.prop is now JSON-serializable <a href="https://github.com/lhorie/mithril.js/issues/54">#54</a></li> <li>m.prop is now JSON-serializable <a href="https://github.com/lhorie/mithril.js/issues/54">#54</a></li>
<li>added <code>extract</code> option to <code>m.request</code> to allow access to response metadata <a href="https://github.com/lhorie/mithril.js/issues/53">#53</a></li> <li>added <code>extract</code> option to <code>m.request</code> to allow access to response metadata <a href="https://github.com/lhorie/mithril.js/issues/53">#53</a></li>
</ul> </ul>
<h3 id="bug-fixes-">Bug Fixes:</h3>
<ul>
<li>Fixed node index displacement by null/undefined nodes <a href="https://github.com/lhorie/mithril.js/issues/56">#56</a></li>
<li>Fixed mock&#39;s insertBefore and appendChild when dealing w/ reattachments</li>
</ul>
<h3 id="breaking-changes-">Breaking changes:</h3> <h3 id="breaking-changes-">Breaking changes:</h3>
<ul> <ul>
<li>changing an id in a virtual element now recreates the element, instead of recycling it <a href="https://github.com/lhorie/mithril.js/issues/55">#55</a></li> <li>changing an id in a virtual element now recreates the element, instead of recycling it <a href="https://github.com/lhorie/mithril.js/issues/55">#55</a></li>

View file

@ -48,18 +48,18 @@ Mithril = m = new function app(window) {
if (dataType == "[object Array]") { if (dataType == "[object Array]") {
var nodes = [], intact = cached.length === data.length, subArrayCount = 0 var nodes = [], intact = cached.length === data.length, subArrayCount = 0
for (var i = 0; i < data.length; i++) { for (var i = 0, cacheCount = 0; i < data.length; i++) {
var item = build(parent, data[i], cached[i], shouldReattach, index + subArrayCount || subArrayCount, namespace) var item = build(parent, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, namespace)
if (item === undefined) continue if (item === undefined) continue
if (!item.nodes.intact) intact = false if (!item.nodes.intact) intact = false
subArrayCount += item instanceof Array ? item.length : 1 subArrayCount += item instanceof Array ? item.length : 1
cached[i] = item cached[cacheCount++] = item
} }
if (!intact) { if (!intact) {
for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes) for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node) for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node) for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node)
cached.length = data.length if (data.length < cached.length) cached.length = data.length
cached.nodes = nodes cached.nodes = nodes
} }
} }
@ -498,9 +498,12 @@ mock.window = new function() {
replaceChild: window.document.replaceChild, replaceChild: window.document.replaceChild,
insertBefore: function(node, reference) { insertBefore: function(node, reference) {
node.parentNode = this node.parentNode = this
var index = this.childNodes.indexOf(reference) var referenceIndex = this.childNodes.indexOf(reference)
if (index < 0) this.childNodes.push(node) if (referenceIndex < 0) this.childNodes.push(node)
else this.childNodes.splice(index, 0, node) else {
var index = this.childNodes.indexOf(node)
this.childNodes.splice(referenceIndex, index < 0 ? 0 : 1, node)
}
}, },
insertAdjacentHTML: function(position, html) { insertAdjacentHTML: function(position, html) {
//todo: accept markup //todo: accept markup
@ -540,6 +543,8 @@ mock.window = new function() {
oldChild.parentNode = null oldChild.parentNode = null
} }
window.document.appendChild = function(child) { window.document.appendChild = function(child) {
var index = this.childNodes.indexOf(child)
if (index > -1) this.childNodes.splice(index, 1)
this.childNodes.push(child) this.childNodes.push(child)
child.parentNode = this child.parentNode = this
} }
@ -899,6 +904,14 @@ function testMithril(mock) {
var elementAfter = root.childNodes[0] var elementAfter = root.childNodes[0]
return elementBefore !== elementAfter return elementBefore !== elementAfter
}) })
test(function() {
//https://github.com/lhorie/mithril.js/issues/56
var root = mock.document.createElement("div")
m.render(root, [null, "foo"])
m.render(root, ["bar"])
console.log(root.childNodes)
return root.childNodes.length == 1
})
//end m.render //end m.render
//m.redraw //m.redraw

View file

@ -48,18 +48,18 @@ Mithril = m = new function app(window) {
if (dataType == "[object Array]") { if (dataType == "[object Array]") {
var nodes = [], intact = cached.length === data.length, subArrayCount = 0 var nodes = [], intact = cached.length === data.length, subArrayCount = 0
for (var i = 0; i < data.length; i++) { for (var i = 0, cacheCount = 0; i < data.length; i++) {
var item = build(parent, data[i], cached[i], shouldReattach, index + subArrayCount || subArrayCount, namespace) var item = build(parent, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, namespace)
if (item === undefined) continue if (item === undefined) continue
if (!item.nodes.intact) intact = false if (!item.nodes.intact) intact = false
subArrayCount += item instanceof Array ? item.length : 1 subArrayCount += item instanceof Array ? item.length : 1
cached[i] = item cached[cacheCount++] = item
} }
if (!intact) { if (!intact) {
for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes) for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node) for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node) for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node)
cached.length = data.length if (data.length < cached.length) cached.length = data.length
cached.nodes = nodes cached.nodes = nodes
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View file

@ -9,6 +9,11 @@
- m.prop is now JSON-serializable [#54](https://github.com/lhorie/mithril.js/issues/54) - m.prop is now JSON-serializable [#54](https://github.com/lhorie/mithril.js/issues/54)
- added `extract` option to `m.request` to allow access to response metadata [#53](https://github.com/lhorie/mithril.js/issues/53) - added `extract` option to `m.request` to allow access to response metadata [#53](https://github.com/lhorie/mithril.js/issues/53)
### Bug Fixes:
- Fixed node index displacement by null/undefined nodes [#56](https://github.com/lhorie/mithril.js/issues/56)
- Fixed mock's insertBefore and appendChild when dealing w/ reattachments
### Breaking changes: ### Breaking changes:
- changing an id in a virtual element now recreates the element, instead of recycling it [#55](https://github.com/lhorie/mithril.js/issues/55) - changing an id in a virtual element now recreates the element, instead of recycling it [#55](https://github.com/lhorie/mithril.js/issues/55)

View file

@ -48,18 +48,18 @@ Mithril = m = new function app(window) {
if (dataType == "[object Array]") { if (dataType == "[object Array]") {
var nodes = [], intact = cached.length === data.length, subArrayCount = 0 var nodes = [], intact = cached.length === data.length, subArrayCount = 0
for (var i = 0; i < data.length; i++) { for (var i = 0, cacheCount = 0; i < data.length; i++) {
var item = build(parent, data[i], cached[i], shouldReattach, index + subArrayCount || subArrayCount, namespace) var item = build(parent, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, namespace)
if (item === undefined) continue if (item === undefined) continue
if (!item.nodes.intact) intact = false if (!item.nodes.intact) intact = false
subArrayCount += item instanceof Array ? item.length : 1 subArrayCount += item instanceof Array ? item.length : 1
cached[i] = item cached[cacheCount++] = item
} }
if (!intact) { if (!intact) {
for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes) for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node) for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node) for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node)
cached.length = data.length if (data.length < cached.length) cached.length = data.length
cached.nodes = nodes cached.nodes = nodes
} }
} }

View file

@ -313,6 +313,14 @@ function testMithril(mock) {
var elementAfter = root.childNodes[0] var elementAfter = root.childNodes[0]
return elementBefore !== elementAfter return elementBefore !== elementAfter
}) })
test(function() {
//https://github.com/lhorie/mithril.js/issues/56
var root = mock.document.createElement("div")
m.render(root, [null, "foo"])
m.render(root, ["bar"])
console.log(root.childNodes)
return root.childNodes.length == 1
})
//end m.render //end m.render
//m.redraw //m.redraw

View file

@ -12,9 +12,12 @@ mock.window = new function() {
replaceChild: window.document.replaceChild, replaceChild: window.document.replaceChild,
insertBefore: function(node, reference) { insertBefore: function(node, reference) {
node.parentNode = this node.parentNode = this
var index = this.childNodes.indexOf(reference) var referenceIndex = this.childNodes.indexOf(reference)
if (index < 0) this.childNodes.push(node) if (referenceIndex < 0) this.childNodes.push(node)
else this.childNodes.splice(index, 0, node) else {
var index = this.childNodes.indexOf(node)
this.childNodes.splice(referenceIndex, index < 0 ? 0 : 1, node)
}
}, },
insertAdjacentHTML: function(position, html) { insertAdjacentHTML: function(position, html) {
//todo: accept markup //todo: accept markup
@ -54,6 +57,8 @@ mock.window = new function() {
oldChild.parentNode = null oldChild.parentNode = null
} }
window.document.appendChild = function(child) { window.document.appendChild = function(child) {
var index = this.childNodes.indexOf(child)
if (index > -1) this.childNodes.splice(index, 1)
this.childNodes.push(child) this.childNodes.push(child)
child.parentNode = this child.parentNode = this
} }