Skip to content

Instantly share code, notes, and snippets.

@davehughes
Created March 2, 2012 02:42
Show Gist options
  • Save davehughes/1955145 to your computer and use it in GitHub Desktop.
Save davehughes/1955145 to your computer and use it in GitHub Desktop.
Experimental Backbone.View extension that takes a declarative approach to dealing with DOM elements.
# Copied from backbone.js
getValue = (object, prop) ->
if not (object and object[prop])
return null
if _.isFunction(object[prop]) then object[prop]() else object[prop]
eventSplitter = /^(\S+)\s*(.*)$/
namedSelectorPattern = /^{(.+)}$/
viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'elements']
###
Adds handling for an 'elements' property mapping names to selectors, allowing
a declarative list of elements of interest similar to the 'events' property.
The delegateEvents function is extended to allow named selector references
in event binding declarations.
class MyView extends ElementalView
elements:
tweetInput: 'input[type=text]'
sendTweet: 'button.send'
events:
'click {tweetButton}': 'sendTweet'
'change {tweetInput}': 'updateValue'
sendTweet:
# look up elements by
@$element('tweetInput').css('background-color', 'red')
###
class ElementalView extends Backbone.View
delegateEvents: (events) ->
if (!(events or (events = getValue(this, 'events')))) then return
@undelegateEvents()
for key, method of events
if not _.isFunction(method) then method = @[method]
if not method then throw new Error("Event handler #{method} does not exist")
match = key.match(eventSplitter)
[m, eventName, selector] = match
method = _.bind(method, this);
eventName += '.delegateEvents' + this.cid
match = selector.match(namedSelectorPattern)
if match
selector = _.map(match[1].split("\\s+"), (s) => @getNamedSelector(s)).join(',')
if selector == ''
@$el.bind(eventName, method)
else
@$el.delegate(selector, eventName, method);
_configure: (options) ->
if @options then options = _.extend({}, @options, options)
_.each viewOptions, (attr) =>
if options[attr] then @[attr] = options[attr]
@options = options
render: -> super; @clearElementCache; return this
getNamedSelector: (name) ->
if _.isFunction(@elements) then @elements = @elements()
return @elements[name]
$element: (name) ->
cached = @_elementCache[name]
if not cached
cached = @_elementCache[name] = @$(@getNamedSelector(name))
return cached
element: (name) -> @$element(name)[0]
elements: -> {}
_elementCache: {}
clearElementCache: -> @_elementCache = {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment