|
|
@@ -1,18 +1,102 @@
|
|
|
+var _ = require('../util')
|
|
|
+
|
|
|
+/**
|
|
|
+ * Listen on the given `event` with `fn`.
|
|
|
+ *
|
|
|
+ * @param {String} event
|
|
|
+ * @param {Function} fn
|
|
|
+ */
|
|
|
+
|
|
|
+exports.$on = function (event, fn) {
|
|
|
+ (this._events[event] || (this._events[event] = []))
|
|
|
+ .push(fn)
|
|
|
+ // increment all parent event count by 1.
|
|
|
+ // pay a small cost here to optimize for $broadcast.
|
|
|
+ var parent = this.$parent
|
|
|
+ while (parent) {
|
|
|
+ parent._eventsCount[event] =
|
|
|
+ (parent._eventsCount[event] || 0) + 1
|
|
|
+ parent = parent.$parent
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Adds an `event` listener that will be invoked a single
|
|
|
+ * time then automatically removed.
|
|
|
+ *
|
|
|
+ * @param {String} event
|
|
|
+ * @param {Function} fn
|
|
|
+ */
|
|
|
+
|
|
|
+exports.$once = function (event, fn) {
|
|
|
+ var self = this
|
|
|
+ function on () {
|
|
|
+ self.$off(event, on)
|
|
|
+ fn.apply(this, arguments)
|
|
|
+ }
|
|
|
+ on.fn = fn
|
|
|
+ this.$on(event, on)
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
- * Proxy basic event methods on the internal emitter.
|
|
|
+ * Remove the given callback for `event` or all
|
|
|
+ * registered callbacks.
|
|
|
+ *
|
|
|
+ * @param {String} event
|
|
|
+ * @param {Function} fn
|
|
|
*/
|
|
|
|
|
|
-;['emit', 'on', 'off', 'once'].forEach(function (method) {
|
|
|
- var realMethod = method === 'emit'
|
|
|
- ? 'applyEmit'
|
|
|
- : method
|
|
|
- exports['$' + method] = function () {
|
|
|
- this._emitter[realMethod].apply(
|
|
|
- this._emitter,
|
|
|
- arguments
|
|
|
- )
|
|
|
+exports.$off = function (event, fn) {
|
|
|
+ // all
|
|
|
+ if (!arguments.length) {
|
|
|
+ this._events = {}
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // specific event
|
|
|
+ var cbs = this._events[event]
|
|
|
+ if (!cbs) return
|
|
|
+ if (arguments.length === 1) {
|
|
|
+ this._events[event] = null
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // specific handler
|
|
|
+ var cb
|
|
|
+ var i = cbs.length
|
|
|
+ while (i--) {
|
|
|
+ cb = cbs[i]
|
|
|
+ if (cb === fn || cb.fn === fn) {
|
|
|
+ cbs.splice(i, 1)
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
-})
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Trigger an event on self.
|
|
|
+ *
|
|
|
+ * @param {String} event
|
|
|
+ */
|
|
|
+
|
|
|
+exports.$emit = function (event) {
|
|
|
+ this._cancelled = false
|
|
|
+ var cbs = this._events[event]
|
|
|
+ if (cbs) {
|
|
|
+ // avoid leaking arguments:
|
|
|
+ // http://jsperf.com/closure-with-arguments
|
|
|
+ var i = arguments.length - 1
|
|
|
+ var args = new Array(i)
|
|
|
+ while (i--) {
|
|
|
+ args[i] = arguments[i + 1]
|
|
|
+ }
|
|
|
+ cbs = _.toArray(cbs)
|
|
|
+ i = 0
|
|
|
+ for (var l = cbs.length; i < l; i++) {
|
|
|
+ if (cbs[i].apply(this, args) === false) {
|
|
|
+ this._eventCancelled = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* Recursively broadcast an event to all children instances.
|
|
|
@@ -21,13 +105,15 @@
|
|
|
* @param {...*} additional arguments
|
|
|
*/
|
|
|
|
|
|
-exports.$broadcast = function () {
|
|
|
+exports.$broadcast = function (event) {
|
|
|
+ // if no child has registered for this event,
|
|
|
+ // then there's no need to broadcast.
|
|
|
+ if (!this._eventsCount[event]) return
|
|
|
var children = this._children
|
|
|
- for (var i = 0, l = children.length; i < l; i++) {
|
|
|
- var child = children[i]
|
|
|
- var emitter = child._emitter
|
|
|
- emitter.applyEmit.apply(emitter, arguments)
|
|
|
- if (!emitter._cancelled) {
|
|
|
+ if (children) {
|
|
|
+ for (var i = 0, l = children.length; i < l; i++) {
|
|
|
+ var child = children[i]
|
|
|
+ child.$emit.apply(child, arguments)
|
|
|
child.$broadcast.apply(child, arguments)
|
|
|
}
|
|
|
}
|
|
|
@@ -41,12 +127,9 @@ exports.$broadcast = function () {
|
|
|
*/
|
|
|
|
|
|
exports.$dispatch = function () {
|
|
|
- var emitter = this._emitter
|
|
|
- emitter.applyEmit.apply(emitter, arguments)
|
|
|
- if (!emitter._cancelled) {
|
|
|
- var parent = this.$parent
|
|
|
- if (parent) {
|
|
|
- parent.$dispatch.apply(parent, arguments)
|
|
|
- }
|
|
|
+ var parent = this.$parent
|
|
|
+ while (parent) {
|
|
|
+ parent.$emit.apply(parent, arguments)
|
|
|
+ parent = parent.$parent
|
|
|
}
|
|
|
}
|