Created
May 7, 2014 15:58
-
-
Save adambeynon/ca4c2a0ba8b3d26d3faf to your computer and use it in GitHub Desktop.
Opal Bound attributes + DOM Compiler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Vienna | |
class BaseBinding | |
def initialize(view, context, node, attr) | |
@view = view | |
@context = context | |
@node = node | |
@attr = attr | |
setup_binding | |
end | |
def destroy | |
puts "destroying #@context -> #@attr for #@observer" | |
@context.remove_observer @attr, @observer | |
end | |
end | |
class ValueBinding < BaseBinding | |
def setup_binding | |
if @attr.include? '|' | |
parts = @attr.partition(/\s+\|\s+/) | |
@attr = parts[0] | |
@filter = parts[2] | |
end | |
observer = proc { |val| value_did_change @node, val } | |
@view.add_view_observer(@context, @attr, observer) | |
if @attr.include? '.' | |
chain = @attr.split '.' | |
current = chain.inject(@context) do |o, p| | |
o.__send__ p | |
end | |
else | |
current = @context.__send__(@attr) | |
end | |
value_did_change @node, current | |
end | |
def value_did_change(node, value) | |
if @filter | |
value = @context.__send__ @filter, value | |
end | |
`$(node).html(#{value.to_s});` | |
end | |
end | |
class InputBinding < ValueBinding | |
def value_did_change(node, value) | |
if @filter | |
value = @context.__send__ @filter, value | |
end | |
`$(node).val(#{value.to_s})` | |
end | |
end | |
class ActionBinding < BaseBinding | |
def setup_binding | |
@element = Element.find @node | |
@handler = @element.on(:click) do |evt| | |
if @context.respond_to? @attr | |
@context.__send__ @attr, evt | |
else | |
raise "Unknown action: #@attr on #@context" | |
end | |
end | |
end | |
def destroy | |
@element.off :click, @handler | |
end | |
end | |
class HideIfBinding < BaseBinding | |
def setup_binding | |
@element = Element.find @node | |
if @attr.include? '.' | |
chain = @attr.split '.' | |
current = chain.inject(@context) do |o, p| | |
o.__send__ p | |
end | |
else | |
current = @context.__send__(@attr) | |
end | |
observer = proc { |val| value_did_change @node, val } | |
@view.add_view_observer @context, @attr, observer | |
value_did_change @node, current | |
end | |
def value_did_change(node, value) | |
@element.toggle(!value) | |
end | |
end | |
class ShowIfBinding < HideIfBinding | |
def value_did_change(node, value) | |
@element.toggle value | |
end | |
end | |
class ViewBinding < BaseBinding | |
def setup_binding | |
view = @context.__send__ @attr | |
view.render | |
Element.find(@node) << view.element | |
end | |
def destroy | |
# do nothing? | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Vienna | |
class DOMCompiler | |
def initialize(view, context) | |
%x{ | |
self.view = view | |
self.node = view.element[0]; | |
self.context = context; | |
self.$compile_tree(self.node); | |
} | |
end | |
def compile_tree(node) | |
%x{ | |
while (node) { | |
self.$compile_node(node); | |
node = self.$next_node(node); | |
} | |
} | |
end | |
def next_node(current) | |
%x{ | |
var children = current.childNodes; | |
if (children && children.length && !((' ' + children[0].className + ' ').indexOf('vienna-view') > -1)) { | |
return children[0]; | |
} | |
var sibling = current.nextSibling; | |
if (self.node === current) { | |
return; | |
} | |
else if (sibling) { | |
return sibling; | |
} | |
var next_parent = current; | |
while (next_parent = next_parent.parentNode) { | |
var parent_sibling = next_parent.nextSibling; | |
if (self.node === next_parent) { | |
return; | |
} | |
else if (parent_sibling) { | |
return parent_sibling; | |
} | |
} | |
return; | |
} | |
end | |
def compile_node(node) | |
%x{ | |
if (node.attributes && node.getAttribute) { | |
var attributes = node.attributes, bindings = []; | |
for (var idx = 0, len = attributes.length; idx < len; idx++) { | |
var attribute = attributes[idx], name = attribute.nodeName; | |
if (!name || name.substr(0, 5) !== 'data-') { | |
continue; | |
} | |
name = name.substr(5); | |
bindings.push([name, attribute.value]); | |
var binding_class; | |
if (name === 'bind') { | |
if (node.tagName.toLowerCase() === 'input') { | |
binding_class = Opal.Vienna.InputBinding; | |
} | |
else { | |
binding_class = Opal.Vienna.ValueBinding; | |
} | |
} | |
else if (name === 'action') { | |
binding_class = Opal.Vienna.ActionBinding; | |
} | |
else if (name === 'hideif') { | |
binding_class = Opal.Vienna.HideIfBinding; | |
} | |
else if (name === 'showif') { | |
binding_class = Opal.Vienna.ShowIfBinding; | |
} | |
else if (name === 'view') { | |
binding_class = Opal.Vienna.ViewBinding; | |
} | |
else { | |
// stop a binding class appearing on next iteration | |
binding_class = null; | |
} | |
if (binding_class) { | |
binding_class.$new(self.view, self.context, node, attribute.value); | |
} | |
else { | |
// console.log("unknown binding class for '" + name + "'"); | |
} | |
} | |
} | |
} | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.row | |
.col-sm-12 | |
Name: | |
%span(data-bind="name") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment