Skip to content

Commit 7c16d97

Browse files
committed
Merge branch 'event-emitter' into v1
2 parents 285938d + 8eece95 commit 7c16d97

10 files changed

+196
-105
lines changed

src/collection.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
Collection.prototype.add = function(model) {
5858
if (!~this.indexOf(model)) {
5959
var length = this.push(model)
60-
this.trigger("add", [model])
60+
this.emit("add", model)
6161
return length
6262
}
6363
}
@@ -90,6 +90,12 @@
9090
return this.at(this.length - 1)
9191
}
9292

93+
Collection.prototype.listenTo = function(emitter) {
94+
emitter
95+
.on("save", this.add, this)
96+
.on("destroy", this.remove, this)
97+
}
98+
9399
Collection.prototype.pluck = function(attribute) {
94100
return this.map(function(model) {
95101
return model.attr(attribute)
@@ -101,7 +107,7 @@
101107

102108
if (~index) {
103109
this.splice(index, 1)
104-
this.trigger("remove", [model])
110+
this.emit("remove", model)
105111
return this.length
106112
}
107113
}
@@ -136,5 +142,7 @@
136142
})
137143
}
138144

139-
Model.Utils.extend(Model.Collection.prototype, Model.Callbacks)
145+
Collection.prototype.on = Model.EventEmitter.prototype.on
146+
Collection.prototype.off = Model.EventEmitter.prototype.off
147+
Collection.prototype.emit = Model.EventEmitter.prototype.emit
140148
})(Model);

src/event_emitter.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
;(function(Model) {
2+
var EventEmitter = Model.EventEmitter = function() {}
3+
4+
function prepareEvent(name) {
5+
if (!this._events) this._events = {}
6+
if (!this._events[name]) this._events[name] = []
7+
return this._events[name]
8+
}
9+
10+
EventEmitter.prototype.off = function(name, callback, scope) {
11+
var events = prepareEvent.call(this, name)
12+
13+
if (callback) {
14+
for (var i = events.length - 1; i >= 0; i--) {
15+
var cb = events[i].callback
16+
var scp = events[i].scope
17+
18+
if (cb === callback && scp === scope) {
19+
events.splice(i, 1)
20+
}
21+
}
22+
} else {
23+
delete this._events[name]
24+
}
25+
26+
return this
27+
}
28+
29+
EventEmitter.prototype.on = function(name, callback, scope) {
30+
prepareEvent.call(this, name).push({ callback: callback, scope: scope })
31+
return this
32+
}
33+
34+
EventEmitter.prototype.emit = function(name) {
35+
var args = Array.prototype.slice.call(arguments, 1)
36+
var events = prepareEvent.call(this, name)
37+
38+
for (var i = 0, length = events.length; i < length; i++) {
39+
var callback = events[i].callback
40+
var scope = events[i].scope || this
41+
callback.apply(scope, args)
42+
}
43+
44+
return this
45+
}
46+
})(Model);

src/model.js

+4
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@ var Model = function(name, func) {
66
this.errors = new Model.Errors(this);
77
this.uid = [name, Model.UID.generate()].join("-")
88
if (Model.Utils.isFunction(this.initialize)) this.initialize()
9+
this.emit("initialize", this)
910
};
1011

1112
// Use module functionality to extend itself onto the constructor. Meta!
1213
Model.Module.extend.call(model, Model.Module)
1314

1415
model._name = name
16+
model.anyInstance = new Model.EventEmitter()
1517
model.collection = new Model.Collection()
1618
model.persistence = Model.NullPersistence
1719
model.unique_key = "id"
1820
model
1921
.extend(Model.Callbacks)
2022
.extend(Model.ClassMethods)
2123

24+
model.collection.listenTo(model.anyInstance)
25+
2226
model.prototype = new Model.Model
2327
model.prototype.constructor = model
2428

src/model_callbacks.js

-40
This file was deleted.

src/model_model.js

+11-6
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ Model.Model.prototype = {
3333

3434
this.constructor.persistence.destroy(this, function(success) {
3535
if (success) {
36-
self.constructor.collection.remove(self)
37-
self.trigger("destroy")
36+
self.emit("destroy", self)
3837
}
3938

4039
if (callback) callback.apply(this, arguments)
@@ -43,6 +42,12 @@ Model.Model.prototype = {
4342
return this;
4443
},
4544

45+
emit: function() {
46+
var anyInstance = this.constructor.anyInstance
47+
anyInstance.emit.apply(anyInstance, arguments)
48+
Model.EventEmitter.prototype.emit.apply(this, arguments)
49+
},
50+
4651
id: function() {
4752
return this.attributes[this.constructor.unique_key];
4853
},
@@ -51,6 +56,9 @@ Model.Model.prototype = {
5156
return this.constructor.persistence.newRecord(this)
5257
},
5358

59+
off: Model.EventEmitter.prototype.off,
60+
on: Model.EventEmitter.prototype.on,
61+
5462
reset: function() {
5563
this.errors.clear();
5664
this.changes = {};
@@ -65,8 +73,7 @@ Model.Model.prototype = {
6573
if (success) {
6674
Model.Utils.extend(self.attributes, self.changes)
6775
self.reset()
68-
self.constructor.collection.add(self)
69-
self.trigger("save")
76+
self.emit("save", self)
7077
}
7178

7279
if (callback) callback.apply(self, arguments)
@@ -92,5 +99,3 @@ Model.Model.prototype = {
9299
return this;
93100
}
94101
};
95-
96-
Model.Utils.extend(Model.Model.prototype, Model.Callbacks)

test/index.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
<!-- js-model -->
1414
<script src="../src/model.js"></script>
15+
<script src="../src/event_emitter.js"></script>
1516
<script src="../src/model_utils.js"></script>
16-
<script src="../src/model_callbacks.js"></script>
1717
<script src="../src/model_class_methods.js"></script>
1818
<script src="../src/collection.js"></script>
1919
<script src="../src/model_errors.js"></script>
@@ -32,8 +32,8 @@
3232
<!-- Tests -->
3333
<script src="tests/model_test.js"></script>
3434
<script src="tests/collection_test.js"></script>
35+
<script src="tests/event_emitter_test.js"></script>
3536
<script src="tests/model_id_test.js"></script>
36-
<script src="tests/model_callbacks_test.js"></script>
3737
<script src="tests/model_class_methods_test.js"></script>
3838
<script src="tests/model_errors_test.js"></script>
3939
<script src="tests/model_module_test.js"></script>

test/tests/event_emitter_test.js

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module("EventEmitter")
2+
3+
test("binding with a scope and emitting with arguments", 3, function() {
4+
var ee = new Model.EventEmitter()
5+
var obj = {}
6+
7+
ee.on("a", function(b, c) {
8+
equals(b, "b")
9+
equals(c, "c")
10+
ok(this === obj)
11+
}, obj)
12+
13+
ee.emit("a", "b", "c")
14+
15+
ee.off("a")
16+
17+
ee.emit("a", "b", "c")
18+
})
19+
20+
test("unbinding by callback", 2, function() {
21+
var ee = new Model.EventEmitter()
22+
var obj = {}
23+
var func1 = function(b, c) {
24+
ok(false)
25+
}
26+
var func2 = function(b, c) {
27+
equals(b, "b")
28+
equals(c, "c")
29+
}
30+
31+
ee.on("a", func1)
32+
ee.on("a", func2)
33+
34+
ee.off("a", func1)
35+
36+
ee.emit("a", "b", "c")
37+
})
38+
39+
test("unbinding by callback and scope", 1, function() {
40+
var ee = new Model.EventEmitter()
41+
var obj = {}
42+
var func = function() {
43+
ok(this !== obj)
44+
}
45+
46+
ee.on("a", func)
47+
ee.on("a", func, obj)
48+
49+
ee.off("a", func, obj)
50+
51+
ee.emit("a")
52+
})

0 commit comments

Comments
 (0)