diff --git a/archive/v0.1.3/change-log.html b/archive/v0.1.3/change-log.html index 370f6374..992906bb 100644 --- a/archive/v0.1.3/change-log.html +++ b/archive/v0.1.3/change-log.html @@ -65,6 +65,7 @@
style attributes and event handlersm.deferred().promise now causes the promise to adopt its state v0.1.2 - maintenance
diff --git a/archive/v0.1.3/mithril-tests.js b/archive/v0.1.3/mithril-tests.js index f75659e5..d6364ce4 100644 --- a/archive/v0.1.3/mithril-tests.js +++ b/archive/v0.1.3/mithril-tests.js @@ -33,7 +33,11 @@ new function(window) { return cell } function build(parent, data, cached) { - if (data === null || data === undefined) return + if (data === null || data === undefined) { + if (cached) clear(cached.nodes) + return + } + if (data.subtree === "retain") return var cachedType = type.call(cached), dataType = type.call(data) if (cachedType != dataType) { @@ -59,8 +63,8 @@ new function(window) { } } else if (dataType == "[object Object]") { - if (typeof data.tag != "string") return if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join()) clear(cached.nodes) + if (typeof data.tag != "string") return var node, isNew = cached.nodes.length === 0 if (isNew) { @@ -640,6 +644,36 @@ function testMithril(mock) { m.render(root, m("div", [m("a", {href: "/second"})])) return root.childNodes[0].childNodes.length == 1 }) + test(function() { + var root = mock.document.createElement("div") + m.render(root, m("ul", [m("li")])) + m.render(root, m("ul", [m("li"), undefined])) + return root.childNodes[0].childNodes.length === 1 + }) + test(function() { + var root = mock.document.createElement("div") + m.render(root, m("ul", [m("li"), m("li")])) + m.render(root, m("ul", [m("li"), undefined])) + return root.childNodes[0].childNodes.length === 1 + }) + test(function() { + var root = mock.document.createElement("div") + m.render(root, m("ul", [m("li")])) + m.render(root, m("ul", [undefined])) + return root.childNodes[0].childNodes.length === 0 + }) + test(function() { + var root = mock.document.createElement("div") + m.render(root, m("ul", [m("li")])) + m.render(root, m("ul", [{}])) + return root.childNodes[0].childNodes.length === 0 + }) + test(function() { + var root = mock.document.createElement("div") + m.render(root, m("ul", [m("li", [m("a")])])) + m.render(root, m("ul", [{subtree: "retain"}])) + return root.childNodes[0].childNodes[0].childNodes[0].nodeName === "A" + }) //m.redraw test(function() { diff --git a/archive/v0.1.3/mithril.html b/archive/v0.1.3/mithril.html index a6d2ec27..76d7bc34 100644 --- a/archive/v0.1.3/mithril.html +++ b/archive/v0.1.3/mithril.html @@ -183,7 +183,8 @@ m("a[href='/dashboard']", {config: m.route}, "Dashboard&q where: VirtualElement :: Object { String tag, Attributes attributes, Children children } Attributes :: Object<any | void config(DOMElement element, Boolean isInitialized)> - Children :: String text | Array<String text | VirtualElement virtualElement | Children children> + Children :: String text | Array<String text | VirtualElement virtualElement | SubtreeDirective directive | Children children> + SubtreeDirective :: Object { String subtree }String selector
This string should be a CSS rule that represents a DOM element.
@@ -259,6 +260,7 @@ m("a[href='/dashboard']", {config: m.route}, "Dashboard&qIf this argument is a string, it will be rendered as a text node. To render a string as HTML, see m.trust
If it's a VirtualElement, it will be rendered as a DOM Element.
If it's a list, its contents will recursively be rendered as appropriate and appended as children of the element being created.
+If it's a SubtreeDirective with the value "retain", it will retain the existing DOM tree in place, if any. See subtree directives for more information.
returns VirtualElement
The returned VirtualElement is a javascript data structure that represents the DOM element to be rendered by m.render
m.render accepts a special low level SubtreeDirective object as a node in a virtual DOM tree: if a tree contains a node that looks exactly like the object below, Mithril will abort the diff algorithm for that node. This allows you to implement optimizations that avoid creating virtual DOM trees in favor of their cached counterparts, if you know they have not changed between redraws. Note that using this feature is discouraged if you don't have visible performance problems.
{subtree: "retain"}
+This mechanism is only intended to be used as a last resort optimization tool. If you do use it, you are responsible for determining what constitutes a scenario where the virtual DOM tree is changed/unchanged.
+The example below shows how to use a SubtreeDirective object to create a static header that doesn't incur diff costs once it has been rendered. This means that we are avoiding the creation of the header subtree (and therefore skipping the diff algorithm) altogether, but it also means that dynamic variables will NOT be updated within the header.
+var app = {}
+
+//here's an example plugin that determines whether data has changes.
+//in this case, it simply assume data has changed the first time, and never changes after that.
+app.bindOnce = new function() {
+ var cache = {}
+ function(view) {
+ if (!cache[view.toString()]) {
+ cache[view.toString()] = true
+ return view()
+ }
+ else return {subtree: "retain"}
+ }
+}
+
+//here's the view
+app.view = function(ctrl) {
+ m(".layout", [
+ app.bindOnce(function() {
+ //this only runs once in order to boost performance
+ //dynamic variables are not updated here
+ return m("header", [
+ m("h1", "this never changes")
+ ])
+ }),
+ //dynamic variables here still update on every redraw
+ m("main", "rest of app goes here")
+ ])
+}
+void render(DOMElement rootElement, Children children)
where:
- Children :: String text | Array<String text | VirtualElement virtualElement | Children children>
+ Children :: String text | Array<String text | VirtualElement virtualElement | SubtreeDirective directive | Children children>
VirtualElement :: Object { String tag, Attributes attributes, Children children }
- Attributes :: Object<Any | void config(DOMElement element)>
+ Attributes :: Object<Any | void config(DOMElement element)>
+ SubtreeDirective :: Object { String subtree }
DOMElement rootElement
A DOM element which will contain the template represented by children.