Created
October 13, 2011 17:55
-
-
Save thejefflarson/1284941 to your computer and use it in GitHub Desktop.
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
// The inspiration for this class is grounded in Jeremy Ashkenas's work with | |
// DocumentCloud. The concept of **bindings** is especially brilliant and is a | |
// large portion of what makes **Glass.js** tick. | |
// | |
propublica.View = Base.extend({ | |
// jquery object for our target | |
el : null, | |
// list of bindings to listen in on | |
bindings : {}, | |
tag : 'div', | |
cssClass : '', | |
toggleClass : 'active', | |
id : '', | |
scope : '', | |
// return if there's an empty query string for abstract views. | |
init : function(){ | |
if(this.query().string.length == 0) return; | |
this._ensureElement(); | |
}, | |
_ensureElement : function(){ | |
this.el = $(this.query().string); | |
this.cid = _.uniqueId(); | |
this.setBindings(); | |
this.el.bind("_render", _.bind(this._render, this)); | |
}, | |
// Delegate to jquery scoped within this.el | |
$ : function(query){ | |
return $(query, this.el); | |
}, | |
// Hidden method that delegates to **render** and is triggered by the initializer. | |
// You probably shouldn't need to overwrite this. | |
_render : function(){ | |
this.render(); | |
return true; | |
}, | |
// override this method with the actual rendering bits | |
render : function(){ | |
return this; | |
}, | |
query : function(){ | |
var self = this; | |
var string = _.reduce([['', 'scope'], [' ', 'tag'], ['#', 'id'], ['.', 'cssClass']], function(memo, attr){ | |
return memo + (self[attr[1]].length > 0 ? attr[0] + self[attr[1]] : ''); | |
}, ''); | |
string = string.replace(/^\s*/, ''); | |
return { | |
string: string, | |
scope: this.scope, | |
tag: this.tag, | |
id: this.id, | |
cssClass: this.cssClass | |
}; | |
}, | |
// ## DOM Manipulation Helpers ## | |
// Although it's possible to directly manipulate the **dom** in a view, its much | |
// more efficient to pass off processing to an associated model. | |
// For example, **munge** takes an **Array** of dom elements, not a jquery object, | |
// and replaces the **View** element's children with the new **collection**. | |
munge : function(collection){ | |
var c = $('<div></div>'); | |
_.each(collection, function(child){ | |
c.append(child); | |
}); | |
this.el.html(c.children()); | |
}, | |
// ## Generic Event Handlers ## | |
// **toggle** adds the **toggleClass** class (by default '.active') or removes it, | |
// in an on and off fashion. Returns the **toggleClass** if it was added. Relies on | |
// the **currentTarget** of the event object rather than **this.el** so you can pre-process | |
// and adjust to the correct target if need be. | |
toggle : function(e){ | |
e.preventDefault(); | |
e.stopPropagation(); | |
var el = $(e.currentTarget); | |
el.toggleClass(this.toggleClass); | |
return el.hasClass(this.toggleClass) ? this.toggleClass : false; | |
}, | |
// gaq tracking for events. You can pass in an array or arguments for the event you | |
// need to track. | |
track : function(){ | |
var args = _.toArray(arguments).slice(0); | |
window._gaq.push((['_trackEvent']).concat(args)); | |
}, | |
// ## Event Bindings ## | |
// sets the bindings and set 'this' back to the the view object | |
setBindings : function(){ | |
var self = this; | |
this.el.unbind(".delegate-" + this.cid); | |
_.each(this.bindings, function(fn, key){ | |
self.el.live(key + ".delegate-" + this.cid, _.bind(self[fn], self)); | |
}); | |
}, | |
// ## Model Communication ## | |
// | |
// bindTo allows you to subscribe to a particular attribute's change event using | |
// simple [Key Value Observing](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html). | |
// So for example if you wanted to listen to events on the title attribute | |
// of a model you would write: | |
// | |
// var view = new propublica.View.extend({ | |
// title_changed : function(e, model, key, old, value){ | |
// console.log(model.read(key)); | |
// } | |
// }); | |
// view.bindTo("title", model); | |
// model.write("title", "New Title"); | |
// >>> "New Title" | |
// | |
// which would automatically call "title_changed" on the view. | |
// | |
// If you want to use a different function than the default -- "{key}_changed" | |
// -- then pass in a *targetKey*. | |
bindTo : function(keyPath, object, targetKey){ | |
keyPath = object.keyPath(keyPath); | |
var cb = targetKey ? this[targetKey] : this[keyPath]; | |
object.bind(keyPath, _.bind(cb, this)); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment