Skip to content

Commit

Permalink
Merge pull request #372 from Shopify/view_argument_bindings
Browse files Browse the repository at this point in the history
View argument directives/bindings
  • Loading branch information
airhorns committed Apr 3, 2012
2 parents 3e58f82 + bf2349c commit 4f1435b
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 17 deletions.
47 changes: 38 additions & 9 deletions lib/batman.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 16 additions & 8 deletions src/batman.coffee
Expand Up @@ -3975,6 +3975,17 @@ class Batman.View extends Batman.Object
@observe 'node', (node) => @render(node)

@store: new Batman.ViewStore()
@option: (keys...) ->
keys.forEach (key) =>
@accessor @::_argumentBindingKey(key), (bindingKey) ->
return unless (node = @get 'node') && (context = @get 'context')
keyPath = node.getAttribute "data-view-#{key}".toLowerCase()
return unless keyPath?
@[bindingKey]?.die()
@[bindingKey] = new Batman.DOM.ViewArgumentBinding node, keyPath, context

@accessor keys..., (key) ->
@get(@_argumentBindingKey(key))?.get('filteredValue')

# Set the source attribute to an html file to have that file loaded.
source: ''
Expand Down Expand Up @@ -4025,6 +4036,8 @@ class Batman.View extends Batman.Object
@_renderer = new Batman.Renderer(node, null, @context, @)
@_renderer.on 'rendered', => @fire('ready', node)

_argumentBindingKey: (key) -> "_#{key}ArgumentBinding"

@::on 'appear', -> @viewDidAppear? arguments...
@::on 'disappear', -> @viewDidDisappear? arguments...
@::on 'beforeAppear', -> @viewWillAppear? arguments...
Expand Down Expand Up @@ -4344,13 +4357,6 @@ Batman.DOM = {
formfor: (node, localName, key, context) ->
new Batman.DOM.FormBinding(arguments...)
context.descendWithKey(key, localName)

view: (node, bindKey, contextKey, context) ->
parent = context.contextForKey(contextKey)
view = null
parent.observeAndFire contextKey, (newValue) ->
view ||= Batman.data node, 'view'
view?.set bindKey, newValue
}

# `Batman.DOM.events` contains the helpers used for binding to events. These aren't called by
Expand Down Expand Up @@ -5441,10 +5447,12 @@ class Batman.DOM.IteratorBinding extends Batman.DOM.AbstractCollectionBinding
@nodeMap.set(item, newNode)
newNode

class Batman.DOM.ViewArgumentBinding extends Batman.DOM.AbstractBinding

# Filters
# -------
#
# `Batman.Filters` contains the simple, determininistic tranforms used in view bindings to
# `Batman.Filters` contains the simple, deterministic transforms used in view bindings to
# make life a little easier.
buntUndefined = (f) ->
(value) ->
Expand Down
1 change: 1 addition & 0 deletions tests/batman/test.html
Expand Up @@ -102,6 +102,7 @@
<script type="text/coffeescript" src="view/unbinding_test.coffee"></script>
<script type="text/coffeescript" src="view/view_binding_test.coffee"></script>
<script type="text/coffeescript" src="view/view_test.coffee"></script>
<script type="text/coffeescript" src="view/view_subclass_test.coffee"></script>
<script type="text/coffeescript" src="view/yield_and_contentfor_test.coffee"></script>
<script type="text/coffeescript">QUnit.start()</script>
</head>
Expand Down
71 changes: 71 additions & 0 deletions tests/batman/view/view_subclass_test.coffee
@@ -0,0 +1,71 @@
helpers = if typeof require is 'undefined' then window.viewHelpers else require './view_helper'

QUnit.module "Batman.View subclasses: argument declaration and passing"

test "should allow class level declaration of arguments", ->
class TestView extends Batman.View
@option 'keyA', 'keyB', "notgiven"

node = $('<div data-view-keyA="one" data-view-keyB="two"/>')[0]
context = Batman one: "foo", two: "bar"
view = new TestView({node, context})
equal view.get('keyA'), "foo"
equal view.get('keyB'), "bar"
equal view.get('notgiven'), undefined

test "should allow keypaths as argument definitions", ->
class TestView extends Batman.View
@option 'test'

node = $('<div data-view-test="foo.bar.baz" />')[0]
context = Batman
foo: Batman
bar: Batman
baz: "qux"

view = new TestView({node, context})
equal view.get('test'), "qux"

test "should track keypath argument changes and update the property on the view", ->
class TestView extends Batman.View
@option 'keyA', 'keyB'

node = $('<div data-view-keyA="one" data-view-keyB="two"/>')[0]
context = Batman one: "foo", two: "bar"
view = new TestView({node, context})
equal view.get('keyA'), "foo"
equal view.get('keyB'), "bar"
context.set 'one', 10
equal view.get('keyA'), 10
equal view.get('keyB'), "bar"

asyncTest "should make the arguments available in the context of the view", ->
class TestView extends Batman.View
@option 'viewKey'

source = '<div data-view="TestView" data-view-viewKey="test"><p data-bind="viewKey"></p></div>'
context = Batman({TestView})

helpers.render source, context, (node) =>
equal $('p', node).html(), ""
context.set "test", "foo"
equal $('p', node).html(), "foo"
context.set "test", "bar"
equal $('p', node).html(), "bar"
QUnit.start()

test "should recreate argument bindings if the view's node changes", ->
class TestView extends Batman.View
@option 'keyA', 'keyB'

initalNode = $('<div data-view-keyA="one" data-view-keyB="two"/>')[0]
newNode = $('<div data-view-keyA="two" data-view-keyB="one"/>')[0]

context = Batman one: "foo", two: "bar"
view = new TestView({node: initalNode, context})
equal view.get('keyA'), "foo"
equal view.get('keyB'), "bar"

view.set 'node', newNode
equal view.get('keyA'), "bar"
equal view.get('keyB'), "foo"

0 comments on commit 4f1435b

Please sign in to comment.