Skip to content

Instantly share code, notes, and snippets.

@olivoil
Created January 19, 2012 20:19
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save olivoil/1642328 to your computer and use it in GitHub Desktop.
Save olivoil/1642328 to your computer and use it in GitHub Desktop.
Mixins/Modules behavior in coffeescript. Thought of to be used with Backbone.js applications
# define module behavior
class Module
keywords = ['extended', 'included', 'initialize']
@extend = (obj) ->
for key, value of obj when key not in keywords
@[key] = value
obj.extended?.apply(@)
this
@include = (obj) ->
for key, value of obj when key not in keywords
@::[key] = value
if obj.initialize?
@::['_initialize_callbacks'] or= []
@::['_initialize_callbacks'].push obj.initialize
obj.included?.apply(@)
this
initialize: ->
if callbacks = @['_initialize_callbacks']
cb.call(@) for cb in callbacks
# define Base classes for the application
Base =
View: class BaseView extends Backbone.View
leave: -> @remove()
Model: class BaseModel extends Backbone.Model
Collection: class BaseCollection extends Backbone.Collection
Router: class BaseRouter extends Backbone.Router
# let Base classes be modules
for name, klass of Base
_(klass).extend Module
_(klass.prototype).extend Module.prototype
# define module 1
Observer =
included: -> console.log "Observer included in #{@name}"
initialize: -> console.log "initialize called from Observer module"
bindTo: (source, event, cb)->
source.bind(event, cb, @)
@bindings or= []
@bindings.push
source: source
event: event
callback: cb
unbindAll: ->
binding.source.unbind(binding.event, binding.callback) for binding in @bindings
@bindings = []
# define module 2
CompositeView =
included: -> console.log "CompositeView included in #{@name}"
initialize: ->
@children = []
console.log 'initialize called from CompositeView module'
addChild: (view)->
@children.push view
view.parent = this
renderChild: (view)->
@addChild(view) unless @hasChild(view)
view.render()
appendChild: (view)->
@renderChild view
($ @el).append view.el
renderChildInto: (view, container)->
@renderChild view
($ container).empty().append view.el
hasChild: (view)->
if (index = @children.indexOf view) != -1
index
else
false
_leaveChildren: -> view.leave?() for view in @children
_removeFromParent: -> @parent?._removeChild @
_removeChild: (view)-> @children.splice(index, 1) if index = @hasChild(view)
Base.View.include Observer # include module 1
class MyView extends Base.View
@include CompositeView # include module 2
initialize: ->
super() # important !
console.log 'initialize called from view definition'
leave: ->
@unbindAll()
@remove()
@_leaveChildren()
@_removeFromParent()
myView1 = new MyView
myView2 = new MyView
myView1.addChild myView2
console.log 'myView1.children', myView1.children #=> contains myView2
console.log 'myView2.children', myView2.children #=> empty
console.log 'MyView instance', myView1 #=> module 1 & 2 are in the prototype chain
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment