299b1c25 by Michael Richards

Implement a portable keypath observer.

1 parent 20f4b3c6
......@@ -20,6 +20,7 @@ module.exports = (grunt) ->
'src/view.coffee'
'src/bindings.coffee'
'src/parsers.coffee'
'src/keypath_observer.coffee'
'src/binders.coffee'
'src/adapters.coffee'
'src/export.coffee'
......
......@@ -27,35 +27,15 @@ class Rivets.Binding
@binder = {routine: @binder} if @binder instanceof Function
setModel: =>
interfaces = (k for k, v of @view.adapters)
tokens = Rivets.KeypathParser.parse @keypath, interfaces, @view.config.rootInterface
@rootKey = tokens.shift()
@key = tokens.pop()
@objectPath ?= []
model = @view.adapters[@rootKey.interface].read @view.models, @rootKey.path
for token, index in tokens
current = @view.adapters[token.interface].read model, token.path
if @objectPath[index]?
if current isnt @objectPath[index]
@view.adapters[token.interface].unsubscribe model, token.path, @setModel
@view.adapters[token.interface].subscribe current, token.path, @setModel
else
@view.adapters[token.interface].subscribe model, token.path, @setModel
model = current
if @model
if @model isnt model
observer = new KeypathObserver @view, @view.models, @keypath, (target) =>
@unbind true if @key
@model = model
@model = target
@bind true if @key
@sync()
else
@model = model
@rootKey = observer.root
@key = observer.key
@model = observer.target
# Applies all the current formatters to the supplied value and returns the
# formatted value.
......
class KeypathObserver
constructor: (@view, @model, @keypath, @callback) ->
@interfaces = (k for k, v of @view.adapters)
@objectPath = []
@tokens = Rivets.KeypathParser.parse @keypath, @interfaces, @view.config.rootInterface
@root = @tokens.shift()
@key = @tokens.pop()
@target = @realize()
update: =>
unless (next = @realize()) is @target
@callback @target = next
realize: =>
current = @view.adapters[@root.interface].read @view.models, @root.path
for token, index in @tokens
next = @view.adapters[token.interface].read current, token.path
if @objectPath[index]?
if next isnt @objectPath[index]
@view.adapters[token.interface].unsubscribe current, token.path, @update
@view.adapters[token.interface].subscribe next, token.path, @update
else
@view.adapters[token.interface].subscribe current, token.path, @update
current = next
current