Last active
August 29, 2015 14:06
-
-
Save alextkachman/8d0ad2bc21307b689819 to your computer and use it in GitHub Desktop.
Any object can be event target
This file contains hidden or 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
angular.module('EventTarget',[]) | |
.run(['$injector',function($injector){ | |
function removeFromList(list,item) { | |
var next = item.next || null | |
var prev = item.prev || null | |
if (prev) { | |
prev.next = next | |
} | |
else { | |
list.first = next | |
} | |
if (next) { | |
next.prev = prev | |
} | |
else { | |
list.last = prev | |
} | |
item.next = item.prev = null | |
return next | |
} | |
Object.defineProperties(Object.prototype, { | |
$event: { | |
value: function(name) { | |
var that = this, | |
capitalized = name.charAt(0).toUpperCase() + name.substr(1) | |
that['on' + capitalized] = function(handler,context) { | |
// NOTICE: if context is scope handler life cycle will be bound to it | |
return this.$addEventListener(name,function(){ | |
handler.apply(this, Array.prototype.slice.call(arguments, 1, arguments.length)) | |
},context) | |
} | |
that['fireOn' + capitalized] = function() { | |
var args = Array.prototype.slice.call(arguments) | |
args.unshift(name); | |
return this.$dispatchEvent.apply(this, args) | |
} | |
}, | |
writable: true | |
}, | |
$dispatchEvent: { | |
value: function(ev) { | |
var listeners = this.$fire$listeners, | |
evListeners | |
if (listeners && (evListeners = listeners[ev])) { | |
var item | |
evListeners.inProgress++ | |
for(item = evListeners.first; item; item = item.next) { | |
if (!item.removed) { | |
try { | |
item.handler.apply(item.context, arguments) | |
} | |
catch(e) { | |
$injector.get('$exceptionHandler')(e) | |
} | |
} | |
} | |
if (!--evListeners.inProgress) { | |
if (evListeners.hasRemoved) { | |
for(item = evListeners.first; item;) { | |
if (item.removed) { | |
item = removeFromList(evListeners, item) | |
if (!--evListeners.hasRemoved) { | |
break | |
} | |
} | |
else { | |
item = item.next | |
} | |
} | |
if (!evListeners.first) { | |
delete listeners[ev] | |
if (!--listeners._count) { | |
// no other event types | |
delete this.$fire$listeners | |
} | |
} | |
} | |
} | |
} | |
}, | |
writable: true | |
}, | |
$addEventListener: { | |
value: function(ev,handler,context) { | |
var that = this; | |
var listeners = that.$fire$listeners || (that.$fire$listeners = {_count:0}); | |
var evListeners = (listeners[ev] || (listeners._count++, listeners[ev] = { | |
inProgress: 0, | |
hasRemoved: 0 | |
})) | |
var item = { | |
handler: handler, | |
context: context || null | |
}; | |
if (!evListeners.first) { | |
evListeners.last = evListeners.first = item | |
} | |
else { | |
evListeners.last.next = item | |
item.prev = evListeners.last | |
evListeners.last = item | |
} | |
// returns remove function | |
var remove = function () { | |
if (!item.removed) { | |
item.removed = true | |
if (!evListeners.inProgress) { | |
removeFromList(evListeners, item) | |
if (!evListeners.first) { | |
delete listeners[ev] | |
if (!--listeners._count) { | |
// no other event types | |
delete that.$fire$listeners | |
} | |
} | |
} | |
else { | |
evListeners.hasRemoved++ | |
} | |
} | |
}; | |
// if context is Scope bind to it's life cycle | |
context && context.$$asyncQueue && context.$on('$destroy',remove) | |
return remove | |
}, | |
writable: true | |
} | |
}); | |
}]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment