From 8fc576490432f5fba56cdb52ddcaf0e847238a5b Mon Sep 17 00:00:00 2001 From: Leo Horie Date: Fri, 4 Jul 2014 23:21:08 -0400 Subject: [PATCH] allow mixing keys with non-keyed elements --- mithril.js | 20 ++++++++++++++------ tests/mithril-tests.js | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/mithril.js b/mithril.js index 02286b46..8e398275 100644 --- a/mithril.js +++ b/mithril.js @@ -49,7 +49,7 @@ Mithril = m = new function app(window) { var nodes = [], intact = cached.length === data.length, subArrayCount = 0 var DELETION = 1, INSERTION = 2 , MOVE = 3 - var existing = {}, shouldMaintainIdentities = false + var existing = {}, unkeyed = [], shouldMaintainIdentities = false for (var i = 0; i < cached.length; i++) { if (cached[i] && cached[i].attrs && cached[i].attrs.key !== undefined) { shouldMaintainIdentities = true @@ -58,15 +58,18 @@ Mithril = m = new function app(window) { } if (shouldMaintainIdentities) { for (var i = 0; i < data.length; i++) { - if (data[i] && data[i].attrs && data[i].attrs.key !== undefined) { - var key = data[i].attrs.key - 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]} + if (data[i] && data[i].attrs) { + if (data[i].attrs.key !== undefined) { + var key = data[i].attrs.key + 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 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++) { if (change.action == DELETION) { @@ -87,6 +90,11 @@ Mithril = m = new function app(window) { 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.nodes = [] for (var i = 0, child; child = parentElement.childNodes[i]; i++) cached.nodes.push(child) diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index 3df6dd0d..1e0efded 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -563,6 +563,23 @@ function testMithril(mock) { 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 }) + 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() { //https://github.com/lhorie/mithril.js/issues/134 var root = mock.document.createElement("div")