Skip to content

Instantly share code, notes, and snippets.

@Plou
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save Plou/56b60c8d69d785ff54bd to your computer and use it in GitHub Desktop.

Select an option

Save Plou/56b60c8d69d785ff54bd to your computer and use it in GitHub Desktop.
An standalone Event class from Backbone in coffeescript
# Create local references to array methods we’ll want to use later.
array = []
push = array.push
slice = array.slice
splice = array.splice
# (Backbone.)Events : A module that can be mixed in to any object in order to provide it with custom events. You may bind with on or remove with off callback functions to an event; trigger-ing an event fires all callbacks in succession.
class Events
# Bind an event to a `callback` function. Passing `"all"` will bind
# the callback to all events fired.
on: (name, callback, context) ->
return @ if not eventsApi(@, "on", name, [
callback
context
]) or not callback
@_events or (@_events = {})
events = @_events[name] or (@_events[name] = [])
events.push
callback: callback
context: context
ctx: context or @
return @
# Bind an event to only be triggered a single time. After the first time
# the callback is invoked, it will be removed.
once: (name, callback, context) ->
return @ if not eventsApi(@, "once", name, [
callback
context
]) or not callback
self = @
once = _.once(->
self.off name, once
callback.apply @, arguments
return
)
once._callback = callback
return @on name, once, context
# Remove one or many callbacks. If `context` is null, removes all
# callbacks with that function. If `callback` is null, removes all
# callbacks for the event. If `name` is null, removes all bound
# callbacks for all events.
off: (name, callback, context) ->
retain = undefined
ev = undefined
events = undefined
names = undefined
i = undefined
l = undefined
j = undefined
k = undefined
return @ if not @_events or not eventsApi(@, "off", name, [
callback
context
])
if not name and not callback and not context
@_events = undefined
return @
names = (if name then [name] else _.keys(@_events))
i = 0
l = names.length
while i < l
name = names[i]
if events = @_events[name]
@_events[name] = retain = []
if callback or context
j = 0
k = events.length
while j < k
ev = events[j]
retain.push ev if (callback and callback isnt ev.callback and callback isnt ev.callback._callback) or (context and context isnt ev.context)
j++
delete @_events[name] unless retain.length
i++
return @
# Trigger one or many events, firing all bound callbacks. Callbacks are
# passed the same arguments as `trigger` is, apart from the event name
# (unless you're listening on `"all"`, which will cause your callback to
# receive the true name of the event as the first argument).
trigger: (name) ->
return @ unless @_events
args = slice.call(arguments, 1)
return @ unless eventsApi(@, "trigger", name, args)
events = @_events[name]
allEvents = @_events.all
triggerEvents events, args if events
triggerEvents allEvents, arguments if allEvents
return @
# Tell @ object to stop listening to either specific events ... or
# to every object it's currently listening to.
stopListening: (obj, name, callback) ->
listeningTo = @_listeningTo
return @ unless listeningTo
remove = not name and not callback
callback = @ if not callback and typeof name is "object"
(listeningTo = {})[obj._listenId] = obj if obj
for id of listeningTo
obj = listeningTo[id]
obj.off name, callback, @
delete @_listeningTo[id] if remove or _.isEmpty(obj._events)
return @
# Regular expression used to split event strings.
eventSplitter = /\s+/
# Implement fancy features of the Events API such as multiple event
# names `"change blur"` and jQuery-style event maps `{change: action}`
# in terms of the existing API.
eventsApi = (obj, action, name, rest) ->
return true unless name
# Handle event maps.
if typeof name is "object"
for key of name
obj[action].apply obj, [
key
name[key]
].concat(rest)
return false
# Handle space separated event names.
if eventSplitter.test(name)
names = name.split(eventSplitter)
i = 0
l = names.length
while i < l
obj[action].apply obj, [names[i]].concat(rest)
i++
return false
return true
# A difficult-to-believe, but optimized internal dispatch function for
# triggering events. Tries to keep the usual cases speedy (most internal
# Backbone events have 3 arguments).
triggerEvents = (events, args) ->
i = -1
l = events.length
a1 = args[0]
a2 = args[1]
a3 = args[2]
switch args.length
when 0
(ev = events[i]).callback.call ev.ctx while ++i < l
return
when 1
(ev = events[i]).callback.call ev.ctx, a1 while ++i < l
return
when 2
(ev = events[i]).callback.call ev.ctx, a1, a2 while ++i < l
return
when 3
(ev = events[i]).callback.call ev.ctx, a1, a2, a3 while ++i < l
return
else
(ev = events[i]).callback.apply ev.ctx, args while ++i < l
return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment