Created
March 2, 2012 02:42
-
-
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.
This file contains 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
# 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