allow mixing keys with non-keyed elements

This commit is contained in:
Leo Horie 2014-07-04 23:21:08 -04:00
parent 9554995a1d
commit 8fc5764904
2 changed files with 31 additions and 6 deletions

View file

@ -49,7 +49,7 @@ Mithril = m = new function app(window) {
var nodes = [], intact = cached.length === data.length, subArrayCount = 0 var nodes = [], intact = cached.length === data.length, subArrayCount = 0
var DELETION = 1, INSERTION = 2 , MOVE = 3 var DELETION = 1, INSERTION = 2 , MOVE = 3
var existing = {}, shouldMaintainIdentities = false var existing = {}, unkeyed = [], shouldMaintainIdentities = false
for (var i = 0; i < cached.length; i++) { for (var i = 0; i < cached.length; i++) {
if (cached[i] && cached[i].attrs && cached[i].attrs.key !== undefined) { if (cached[i] && cached[i].attrs && cached[i].attrs.key !== undefined) {
shouldMaintainIdentities = true shouldMaintainIdentities = true
@ -58,15 +58,18 @@ Mithril = m = new function app(window) {
} }
if (shouldMaintainIdentities) { if (shouldMaintainIdentities) {
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
if (data[i] && data[i].attrs && data[i].attrs.key !== undefined) { if (data[i] && data[i].attrs) {
var key = data[i].attrs.key if (data[i].attrs.key !== undefined) {
if (!existing[key]) existing[key] = {action: INSERTION, index: i} var key = data[i].attrs.key
else existing[key] = {action: MOVE, index: i, from: existing[key].index, element: parentElement.childNodes[existing[key].index]} if (!existing[key]) existing[key] = {action: INSERTION, index: i}
else existing[key] = {action: MOVE, index: i, from: existing[key].index, element: parentElement.childNodes[existing[key].index]}
}
else unkeyed.push({index: i, element: parentElement.childNodes[i]})
} }
} }
var actions = Object.keys(existing).map(function(key) {return existing[key]}) var actions = Object.keys(existing).map(function(key) {return existing[key]})
var changes = actions.sort(function(a, b) {return a.action - b.action || b.index - a.index}) var changes = actions.sort(function(a, b) {return a.action - b.action || b.index - a.index})
var newCached = new Array(cached.length) var newCached = cached.slice()
for (var i = 0, change; change = changes[i]; i++) { for (var i = 0, change; change = changes[i]; i++) {
if (change.action == DELETION) { if (change.action == DELETION) {
@ -87,6 +90,11 @@ Mithril = m = new function app(window) {
newCached[change.index] = cached[change.from] newCached[change.index] = cached[change.from]
} }
} }
for (var i = 0; i < unkeyed.length; i++) {
var change = unkeyed[i]
parentElement.insertBefore(change.element, parentElement.childNodes[change.index])
newCached[change.index] = cached[change.index]
}
cached = newCached cached = newCached
cached.nodes = [] cached.nodes = []
for (var i = 0, child; child = parentElement.childNodes[i]; i++) cached.nodes.push(child) for (var i = 0, child; child = parentElement.childNodes[i]; i++) cached.nodes.push(child)

View file

@ -563,6 +563,23 @@ function testMithril(mock) {
var fourthAfter = root.childNodes[0] var fourthAfter = root.childNodes[0]
return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].key == "10" && root.childNodes[4].key == "6" && root.childNodes[5].key == "7" && root.childNodes.length === 6 return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].key == "10" && root.childNodes[4].key == "6" && root.childNodes[5].key == "7" && root.childNodes.length === 6
}) })
test(function() {
//https://github.com/lhorie/mithril.js/issues/149
var root = mock.document.createElement("div")
m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a"), m("a", {key: 4}), m("a", {key: 5})])
var firstBefore = root.childNodes[0]
var secondBefore = root.childNodes[1]
var thirdBefore = root.childNodes[2]
var fourthBefore = root.childNodes[3]
var fifthBefore = root.childNodes[4]
m.render(root, [m("a", {key: 4}), m("a", {key: 5}), m("a"), m("a", {key: 1}), m("a", {key: 2})])
var firstAfter = root.childNodes[3]
var secondAfter = root.childNodes[4]
var thirdAfter = root.childNodes[2]
var fourthAfter = root.childNodes[0]
var fifthAfter = root.childNodes[1]
return firstBefore === firstAfter && secondBefore === secondAfter && thirdBefore === thirdAfter && fourthBefore === fourthAfter && fifthBefore === fifthAfter
})
test(function() { test(function() {
//https://github.com/lhorie/mithril.js/issues/134 //https://github.com/lhorie/mithril.js/issues/134
var root = mock.document.createElement("div") var root = mock.document.createElement("div")