Skip to content

Commit f3d0d7e

Browse files
committed
initial triggerThen commit
1 parent 877b77e commit f3d0d7e

File tree

6 files changed

+223
-0
lines changed

6 files changed

+223
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
raw
2+
*.sw?
3+
.DS_Store
4+
npm-debug.log
5+
node_modules

.npmignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test/

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2013 Tim Griesser
2+
3+
Permission is hereby granted, free of charge, to any person
4+
obtaining a copy of this software and associated documentation
5+
files (the "Software"), to deal in the Software without
6+
restriction, including without limitation the rights to use,
7+
copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the
9+
Software is furnished to do so, subject to the following
10+
conditions:
11+
12+
The above copyright notice and this permission notice shall be
13+
included in all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.

package.json

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "trigger-then",
3+
"main": "trigger-then.js",
4+
"author": {
5+
"name": "Tim Griesser"
6+
},
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/tgriesser/trigger-then"
10+
},
11+
"description": "Adding 'promise' triggers to Backbone events",
12+
"version": "0.1.0",
13+
"license": "MIT",
14+
"readmeFilename": "README.md",
15+
"scripts": {
16+
"test": "mocha -R spec test/index.js"
17+
},
18+
"devDependencies": {
19+
"backbone": "1.0.x",
20+
"mocha": "1.7.x",
21+
"when": "2.1.x",
22+
"q": "0.9.x"
23+
},
24+
"dependencies": {},
25+
"keywords": [
26+
"backbone",
27+
"deferred",
28+
"promise",
29+
"events"
30+
]
31+
}

test/index.js

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
var assert = require('assert');
2+
var equal = assert.equal;
3+
var deepEqual = assert.deepEqual;
4+
5+
var triggerThen = require('../trigger-then');
6+
var Backbone = require('backbone');
7+
var Q = require('q');
8+
var When = require('when');
9+
10+
describe('triggerThen', function(value) {
11+
12+
it('should take two arguments, the Backbone instance and the promise lib', function() {
13+
triggerThen(Backbone, Q.all);
14+
equal(typeof Backbone.Events.triggerThen === 'function', true);
15+
});
16+
17+
it('should swap out the promise lib if called more than once', function() {
18+
triggerThen(Backbone, When.all);
19+
});
20+
21+
it('should trigger events, returning a promise the event', function(ok) {
22+
var model = new (Backbone.Model.extend({
23+
initialize: function() {
24+
this.on('fireEvent', this.regularFn, this);
25+
this.on('fireEvent', this.dfdFn, this);
26+
this.on('errorEvent', this.errorFn, this);
27+
},
28+
regularFn: function(time) {
29+
return time;
30+
},
31+
dfdFn: function(time) {
32+
var dfd = Q.defer();
33+
setTimeout(function() {
34+
dfd.resolve('This is a deferred object');
35+
}, time);
36+
return dfd.promise;
37+
},
38+
errorFn: function(time) {
39+
var dfd = When.defer();
40+
setTimeout(function() {
41+
dfd.reject(new Error('This is a failed promise'));
42+
}, time);
43+
return dfd.promise;
44+
}
45+
}))();
46+
47+
model.trigger('fireEvent', 50);
48+
model.triggerThen('fireEvent', 50).then(function(resp) {
49+
equal(resp[0], 50);
50+
equal(resp[1], 'This is a deferred object');
51+
})
52+
.then(function() {
53+
return model.trigger('fireEvent errorEvent', 10);
54+
})
55+
.then(function() {
56+
return model.triggerThen('fireEvent errorEvent', 10);
57+
})
58+
.then(null, function(e) {
59+
equal(e.toString(), 'Error: This is a failed promise');
60+
ok();
61+
});
62+
});
63+
64+
it('should resolve properly if there is no name', function(ok) {
65+
Backbone.triggerThen().then(function() {
66+
return Backbone.triggerThen('noname');
67+
})
68+
.then(function() {
69+
ok();
70+
});
71+
});
72+
73+
it('should handle "all" properly', function(ok) {
74+
var model = new (Backbone.Model.extend({
75+
initialize: function() {
76+
this.on('fireEvent', this.regularFn, this);
77+
this.on('all', this.dfdFn, this);
78+
},
79+
regularFn: function(time) {
80+
return time;
81+
},
82+
dfdFn: function(time) {
83+
var dfd = Q.defer();
84+
setTimeout(function() {
85+
dfd.resolve('This is a deferred object');
86+
}, time);
87+
return dfd.promise;
88+
}
89+
}))();
90+
91+
model.trigger('fireEvent', 10);
92+
model.triggerThen('fireEvent', 10).then(function(resp) {
93+
equal(resp[0], 10);
94+
equal(resp[1], 'This is a deferred object');
95+
ok();
96+
});
97+
98+
});
99+
100+
101+
});

trigger-then.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Exports the function which mixes `triggerThen`
2+
// into the specified `Backbone` copy's `Events` object,
3+
// using the promise-lib's "all" implementation provided
4+
// in the second argument.
5+
(function(mixinFn) {
6+
if (typeof exports === "object") {
7+
module.exports = mixinFn;
8+
} else if (typeof define === "function" && define.amd) {
9+
define('trigger-then', [], function() { return mixinFn; });
10+
} else {
11+
this.triggerThen = mixinFn;
12+
}
13+
}).call(this, function(Backbone, All) {
14+
15+
var Events = Backbone.Events;
16+
var push = Array.prototype.push;
17+
var slice = Array.prototype.slice;
18+
var eventSplitter = /\s+/;
19+
20+
// A difficult-to-believe, but optimized internal dispatch function for
21+
// triggering events. Tries to keep the usual cases speedy (most internal
22+
// Backbone events have 3 arguments). Returns an array containing all of the
23+
// event trigger calls, in case any return deferreds.
24+
var triggerEvents = function(events, args) {
25+
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
26+
var dfds = [];
27+
switch (args.length) {
28+
case 0: while (++i < l) dfds.push((ev = events[i]).callback.call(ev.ctx)); return dfds;
29+
case 1: while (++i < l) dfds.push((ev = events[i]).callback.call(ev.ctx, a1)); return dfds;
30+
case 2: while (++i < l) dfds.push((ev = events[i]).callback.call(ev.ctx, a1, a2)); return dfds;
31+
case 3: while (++i < l) dfds.push((ev = events[i]).callback.call(ev.ctx, a1, a2, a3)); return dfds;
32+
default: while (++i < l) dfds.push((ev = events[i]).callback.apply(ev.ctx, args)); return dfds;
33+
}
34+
};
35+
36+
// Fires events as `trigger` normally would, but assumes that some of the `return`
37+
// values from the events may be promises, and and returns a promise when all of the
38+
// events are resolved.
39+
var triggerThen = Events.triggerThen = function(name) {
40+
if (!this._events) return All([]);
41+
var names = [name];
42+
var args = slice.call(arguments, 1);
43+
var dfds = [];
44+
var events = [];
45+
if (eventSplitter.test(names[0])) names = names[0].split(eventSplitter);
46+
for (var i = 0, l = names.length; i < l; i++) {
47+
push.apply(events, this._events[names[i]]);
48+
}
49+
var allEvents = this._events.all;
50+
if (events) push.apply(dfds, triggerEvents(events, args));
51+
if (allEvents) push.apply(dfds, triggerEvents(allEvents, arguments));
52+
return All(dfds);
53+
};
54+
55+
// Mixin `triggerThen` to the appropriate objects and prototypes.
56+
Backbone.triggerThen = triggerThen;
57+
58+
var objs = ['Model', 'Collection', 'Router', 'View', 'History'];
59+
60+
for (var i=0, l=objs.length; i<l; i++) {
61+
Backbone[objs[i]].prototype.triggerThen = triggerThen;
62+
}
63+
});

0 commit comments

Comments
 (0)