diff --git a/opal/clearwater/black_box_node.rb b/opal/clearwater/black_box_node.rb index 27fd147..22a60d4 100644 --- a/opal/clearwater/black_box_node.rb +++ b/opal/clearwater/black_box_node.rb @@ -20,9 +20,15 @@ def render Renderable.new(self) end + def key + end + class Renderable def initialize delegate @delegate = delegate + if delegate.key + @key = delegate.key + end end def wrap node @@ -52,7 +58,14 @@ def create_element // node: a Bowser-wrapped version of the DOM node Opal.defn(self, 'update', function(previous, node) { var self = this; - #{@delegate.update(`previous.delegate`, wrap(`node`))}; + if(self.delegate.$$class === previous.delegate.$$class) { + #{@delegate.update(`previous.delegate`, wrap(`node`))}; + } else { + previous.destroy(#{wrap(`node`)}); + var new_node = #{create_element}; + #{@delegate.mount(`new_node`)}; + return new_node.native; + } }); // virtual-dom destroy hook diff --git a/opal/clearwater/cached_render.rb b/opal/clearwater/cached_render.rb index be13d21..238fcd7 100644 --- a/opal/clearwater/cached_render.rb +++ b/opal/clearwater/cached_render.rb @@ -13,7 +13,6 @@ def should_render? _ end def key - `undefined` end end end diff --git a/opal/clearwater/cached_render/wrapper.rb b/opal/clearwater/cached_render/wrapper.rb index 8c291d0..48aba05 100644 --- a/opal/clearwater/cached_render/wrapper.rb +++ b/opal/clearwater/cached_render/wrapper.rb @@ -5,7 +5,7 @@ class Wrapper def initialize content @content = content - @key = content.key + @key = content.key if content.key end # Hook into vdom diff/patch diff --git a/opal/clearwater/memoized_component.rb b/opal/clearwater/memoized_component.rb new file mode 100644 index 0000000..6dcbcd9 --- /dev/null +++ b/opal/clearwater/memoized_component.rb @@ -0,0 +1,75 @@ +require 'clearwater/component' +require 'clearwater/black_box_node' + +module Clearwater + class MemoizedComponent + include Clearwater::Component + + def self.memoize *args, &block + Placeholder.new(self, args, block) + end + + def self.[] key + memoize[key] + end + + def update + end + + def destroy + end + + class Placeholder + include Clearwater::BlackBoxNode + + attr_reader :klass, :key, :vdom + + def initialize klass, args, block + @klass = klass + @args = args + @block = block + end + + def memoize *args, &block + initialize @klass, args, block + self + end + + def [] key + @key = key.to_s + self + end + + def component + @component ||= @klass.new(*@args, &@block) + end + + def node + @node ||= Clearwater::Component.sanitize_content(component) + end + + def mount element + @vdom = VirtualDOM::Document.new(element) + + # TODO: add a public interface to generate a pre-initialized VDOM::Doc + `#@vdom.tree = #{element.to_n}` + `#@vdom.node = #{node}` + `#@vdom.rendered = true` + end + + def update previous + @vdom = previous.vdom + @component = previous.component + + if component.should_update?(*@args, &@block) + component.update(*@args, &@block) + @vdom.render component.render + end + end + + def unmount + component.destroy + end + end + end +end diff --git a/opal/clearwater/virtual_dom.rb b/opal/clearwater/virtual_dom.rb index 5607abf..4e23f21 100644 --- a/opal/clearwater/virtual_dom.rb +++ b/opal/clearwater/virtual_dom.rb @@ -46,7 +46,7 @@ def self.sanitize_content content end class Document - def initialize(root=Bowser.document.create_element('div')) + def initialize(root=Bowser.document.create_element(:div)) @root = root end diff --git a/spec-opal/clearwater/black_box_node_spec.rb b/spec-opal/clearwater/black_box_node_spec.rb index e2d2680..d81c6d2 100644 --- a/spec-opal/clearwater/black_box_node_spec.rb +++ b/spec-opal/clearwater/black_box_node_spec.rb @@ -29,7 +29,7 @@ def mounted? end end.new } - let(:renderable) { BlackBoxNode::Renderable.new(object) } + let(:renderable) { object.render } it 'has the special type of "Widget"' do r = renderable @@ -55,8 +55,7 @@ def mounted? end it 'calls update when updated in the DOM' do - r = renderable - `r.update({})` + `#{renderable}.update(#{renderable.dup})` expect(object.last_update).not_to be_nil end