From d44176c888d6b76fab7c7017632c505799a84b99 Mon Sep 17 00:00:00 2001 From: Leo Horie Date: Tue, 1 Jul 2014 22:26:12 -0400 Subject: [PATCH] re-render from scratch on route changes --- docs/change-log.md | 4 +++ mithril.js | 18 ++++++++--- tests/mithril-tests.js | 70 ++++++++++++++++-------------------------- 3 files changed, 44 insertions(+), 48 deletions(-) diff --git a/docs/change-log.md b/docs/change-log.md index c8d4c343..454e2b8b 100644 --- a/docs/change-log.md +++ b/docs/change-log.md @@ -5,12 +5,16 @@ ### News: - config contexts can now have an `onunload` property for clean up tasks after elements are detached from the document +- route changes now re-render from scratch, rather than attempting a virtual dom diff +- virtual elements that are children of an array can now accept a `key` attribute which maintains the identity of the underlying DOM elements when the array gets shuffled [#98](https://github.com/lhorie/mithril.js/issues/98) ### Bug Fixes: - fixed a subtree directive bug that happened in inputs inside loops - fixed select.value so that the correct option is displayed on first render - in m.request, non-idempotent methods now automatically send appropriate Content-Type header if `serialize` is `JSON.stringify` [#139](https://github.com/lhorie/mithril.js/issues/139) +- `m` selectors now correctly handle empty attribute values like `[href='']` +- pre-existing nodes in a root element now get cleared if there's no cell cache associated with the element [#60](https://github.com/lhorie/mithril.js/issues/60) --- diff --git a/mithril.js b/mithril.js index dd16550b..bb74230e 100644 --- a/mithril.js +++ b/mithril.js @@ -297,12 +297,16 @@ Mithril = m = new function app(window) { m.render = function(root, cell) { var configs = [] if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.") - var index = nodeCache.indexOf(root) - var id = index < 0 ? nodeCache.push(root) - 1 : index + var id = getCellCacheId(root) var node = root == window.document || root == window.document.documentElement ? documentNode : root + if (cellCache[id] === undefined) clear(node.childNodes) cellCache[id] = build(node, null, undefined, undefined, cell, cellCache[id], false, 0, null, undefined, configs) for (var i = 0; i < configs.length; i++) configs[i]() } + function getCellCacheId(element) { + var index = nodeCache.indexOf(element) + return index < 0 ? nodeCache.push(element) - 1 : index + } m.trust = function(value) { value = new String(value) @@ -428,17 +432,23 @@ Mithril = m = new function app(window) { } for (var route in router) { - if (route == path) return !void m.module(root, router[route]) + if (route == path) { + clear(root.childNodes, cellCache[getCellCacheId(root)]) + m.module(root, router[route]) + return true + } var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$") if (matcher.test(path)) { - return !void path.replace(matcher, function() { + clear(root.childNodes, cellCache[getCellCacheId(root)]) + path.replace(matcher, function() { var keys = route.match(/:[^\/]+/g) || [] var values = [].slice.call(arguments, 1, -2) for (var i = 0; i < keys.length; i++) routeParams[keys[i].replace(/:|\./g, "")] = decodeSpace(values[i]) m.module(root, router[route]) }) + return true } } } diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index 9568e988..c71f75b6 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -577,6 +577,32 @@ function testMithril(mock) { m.render(root, m("textarea", ["test1"])) return root.childNodes[0].value === "test1" }) + test(function() { + var root = mock.document.createElement("div") + var unloaded = 0 + m.render(root, [ + m("div", { + key: 1, + config: function(el, init, ctx) { + ctx.onunload = function() { + unloaded++ + } + } + }) + ]) + m.render(root, [ + m("div", {key: 2}), + m("div", { + key: 1, + config: function(el, init, ctx) { + ctx.onunload = function() { + unloaded++ + } + } + }) + ]) + return unloaded == 0 + }) //end m.render //m.redraw @@ -1028,50 +1054,6 @@ function testMithril(mock) { mock.performance.$elapse(50) //setup mock.location.search = "?" - var root = mock.document.createElement("div") - var unloaded = 0 - m.route.mode = "search" - m.route(root, "/", { - "/": { - controller: function() {}, - view: function() { - return [ - m("div", { - key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { - unloaded++ - } - } - }) - ] - } - }, - "/test19": { - controller: function() {}, - view: function() { - return [ - m("div", { - key: 1, - config: function(el, init, ctx) { - ctx.onunload = function() { - unloaded++ - } - } - }) - ] - } - } - }) - mock.performance.$elapse(50) - m.route("/test19") - mock.performance.$elapse(50) //teardown - return unloaded == 0 - }) - test(function() { - mock.performance.$elapse(50) //setup - mock.location.search = "?" - var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search"