diff --git a/render/render.js b/render/render.js
index 731ebdf3..c71177e9 100644
--- a/render/render.js
+++ b/render/render.js
@@ -97,7 +97,9 @@ module.exports = function($window) {
function createComponent(vnode, hooks, ns) {
// For object literals since `Vnode()` always sets the `state` field.
if (!vnode.state) vnode.state = {}
- assign(vnode.state, vnode.tag)
+ var constructor = function() {}
+ constructor.prototype = vnode.tag
+ vnode.state = new constructor
var view = vnode.tag.view
if (view.reentrantLock != null) return $emptyFragment
@@ -380,12 +382,18 @@ module.exports = function($window) {
function removeNode(vnode, context) {
var expected = 1, called = 0
if (vnode.attrs && vnode.attrs.onbeforeremove) {
- expected++
- vnode.attrs.onbeforeremove.call(vnode.state, vnode, once(continuation))
+ var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode)
+ if (result != null && typeof result.then === "function") {
+ expected++
+ result.then(continuation, continuation)
+ }
}
if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
- expected++
- vnode.tag.onbeforeremove.call(vnode.state, vnode, once(continuation))
+ var result = vnode.tag.onbeforeremove.call(vnode.state, vnode)
+ if (result != null && typeof result.then === "function") {
+ expected++
+ result.then(continuation, continuation)
+ }
}
continuation()
function continuation() {
@@ -559,10 +567,6 @@ module.exports = function($window) {
return false
}
- function assign(target, source) {
- Object.keys(source).forEach(function(k){target[k] = source[k]})
- }
-
function render(dom, vnodes) {
if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
var hooks = []
diff --git a/render/tests/index.html b/render/tests/index.html
index 3cc2da65..480b8b7c 100644
--- a/render/tests/index.html
+++ b/render/tests/index.html
@@ -14,6 +14,7 @@
+
diff --git a/render/tests/test-component.js b/render/tests/test-component.js
index d6d26e43..f4aad629 100644
--- a/render/tests/test-component.js
+++ b/render/tests/test-component.js
@@ -588,14 +588,12 @@ o.spec("component", function() {
o("calls onbeforeremove", function() {
var called = 0
var component = {
- onbeforeremove: function(vnode, done) {
+ onbeforeremove: function(vnode) {
called++
o(vnode.dom).notEquals(undefined)
o(vnode.dom).equals(root.firstChild)
o(root.childNodes.length).equals(1)
-
- done()
},
view: function() {
return {tag: "div", attrs: {id: "a"}, text: "b"}
@@ -614,14 +612,12 @@ o.spec("component", function() {
o("calls onbeforeremove when returning fragment", function() {
var called = 0
var component = {
- onbeforeremove: function(vnode, done) {
+ onbeforeremove: function(vnode) {
called++
o(vnode.dom).notEquals(undefined)
o(vnode.dom).equals(root.firstChild)
o(root.childNodes.length).equals(1)
-
- done()
},
view: function() {
return [{tag: "div", attrs: {id: "a"}, text: "b"}]
@@ -672,6 +668,10 @@ o.spec("component", function() {
function init(vnode) {
o(vnode.state.data).deepEquals(data)
o(vnode.state.data).equals(data)
+
+ //inherits state via prototype
+ component.x = 1
+ o(vnode.state.x).equals(1)
}
})
o("state copy is shallow", function() {
diff --git a/render/tests/test-onbeforeremove.js b/render/tests/test-onbeforeremove.js
index 84e9077c..82a859d0 100644
--- a/render/tests/test-onbeforeremove.js
+++ b/render/tests/test-onbeforeremove.js
@@ -4,6 +4,7 @@ var o = require("../../ospec/ospec")
var callAsync = require("../../test-utils/callAsync")
var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render")
+var Promise = require("../../promise/promise")
o.spec("onbeforeremove", function() {
var $window, root, render
@@ -43,17 +44,13 @@ o.spec("onbeforeremove", function() {
render(root, [vnode])
render(root, [])
- function remove(node, complete) {
+ function remove(node) {
o(node).equals(vnode)
o(this).equals(vnode.state)
o(root.childNodes.length).equals(1)
o(root.firstChild).equals(vnode.dom)
callAsync(function() {
- o(root.childNodes.length).equals(1)
-
- complete()
-
o(root.childNodes.length).equals(0)
done()
@@ -66,16 +63,12 @@ o.spec("onbeforeremove", function() {
render(root, [vnode])
render(root, [])
- function remove(node, complete) {
+ function remove(node) {
o(node).equals(vnode)
o(root.childNodes.length).equals(1)
o(root.firstChild).equals(vnode.dom)
callAsync(function() {
- o(root.childNodes.length).equals(1)
-
- complete()
-
o(root.childNodes.length).equals(0)
done()
@@ -88,16 +81,12 @@ o.spec("onbeforeremove", function() {
render(root, [vnode])
render(root, [])
- function remove(node, complete) {
+ function remove(node) {
o(node).equals(vnode)
o(root.childNodes.length).equals(1)
o(root.firstChild).equals(vnode.dom)
callAsync(function() {
- o(root.childNodes.length).equals(1)
-
- complete()
-
o(root.childNodes.length).equals(0)
done()
@@ -110,16 +99,12 @@ o.spec("onbeforeremove", function() {
render(root, [vnode])
render(root, [])
- function remove(node, complete) {
+ function remove(node) {
o(node).equals(vnode)
o(root.childNodes.length).equals(1)
o(root.firstChild).equals(vnode.dom)
callAsync(function() {
- o(root.childNodes.length).equals(1)
-
- complete()
-
o(root.childNodes.length).equals(0)
done()
@@ -133,17 +118,12 @@ o.spec("onbeforeremove", function() {
render(root, [vnode])
render(root, [])
- function remove(node, complete) {
+ function remove(node) {
o(node).equals(vnode)
o(root.childNodes.length).equals(1)
o(root.firstChild).equals(vnode.dom)
callAsync(function() {
- o(root.childNodes.length).equals(1)
- o(spy.callCount).equals(0)
-
- complete()
-
o(root.childNodes.length).equals(0)
o(spy.callCount).equals(1)
@@ -161,7 +141,7 @@ o.spec("onbeforeremove", function() {
o(vnode.dom.attributes["onbeforeremove"]).equals(undefined)
})
o("does not recycle when there's an onbeforeremove", function() {
- var remove = function(vnode, done) {done()}
+ var remove = function(vnode) {}
var vnode = {tag: "div", key: 1, attrs: {onbeforeremove: remove}}
var updated = {tag: "div", key: 1, attrs: {onbeforeremove: remove}}
@@ -171,9 +151,8 @@ o.spec("onbeforeremove", function() {
o(vnode.dom).notEquals(updated.dom)
})
- o("does not leave elements out of order during removal", function() {
- var finish
- var remove = function(vnode, done) {finish = done}
+ o("does not leave elements out of order during removal", function(done) {
+ var remove = function(vnode) {return Promise.resolve()}
var vnodes = [{tag: "div", key: 1, attrs: {onbeforeremove: remove}, text: "1"}, {tag: "div", key: 2, attrs: {onbeforeremove: remove}, text: "2"}]
var updated = {tag: "div", key: 2, attrs: {onbeforeremove: remove}, text: "2"}
@@ -183,14 +162,16 @@ o.spec("onbeforeremove", function() {
o(root.childNodes.length).equals(2)
o(root.firstChild.firstChild.nodeValue).equals("1")
- finish()
-
- o(root.childNodes.length).equals(1)
- o(root.firstChild.firstChild.nodeValue).equals("2")
+ callAsync(function() {
+ o(root.childNodes.length).equals(1)
+ o(root.firstChild.firstChild.nodeValue).equals("2")
+
+ done()
+ })
})
- o("finalizes the remove phase only once when `done()` is called synchronously from both attrs- and tag.onbeforeremove", function() {
+ o("finalizes the remove phase asynchronously when promise is returned synchronously from both attrs- and tag.onbeforeremove", function(done) {
var onremove = o.spy()
- var onbeforeremove = function(vnode, done){done()}
+ var onbeforeremove = function(){return Promise.resolve()}
var component = {
onbeforeremove: onbeforeremove,
onremove: onremove,
@@ -198,30 +179,9 @@ o.spec("onbeforeremove", function() {
}
render(root, [{tag: component, attrs: {onbeforeremove: onbeforeremove, onremove: onremove}}])
render(root, [])
- o(onremove.callCount).equals(2) // once for `tag`, once for `attrs`
- })
- o("doesn't finalize prematurely if `done` is called twice in the `tag` hook", function(done) {
- var async = false
- var component = {
- view: function() {},
- onbeforeremove: function(vnode, doneRemoving){
- doneRemoving()
- doneRemoving()
- },
- onremove: function() {
- o(async).equals(true)
- done()
- },
- }
- render(root, [{
- tag:component,
- attrs: {
- onbeforeremove: function(vnode, doneRemoving){
- callAsync(doneRemoving)
- }
- }
- }])
- render(root, [])
- async = true
+ callAsync(function() {
+ o(onremove.callCount).equals(2) // once for `tag`, once for `attrs`
+ done()
+ })
})
})