Skip to content

Commit dd4bec8

Browse files
author
Ben McCormick
committed
Add first class support for Backbone.Radio in Mn.Object
- Radio added as a dependency - Mn.Object now supports radioEvents, radioCommands, and radioRequests hashes in the form `{'channel message':'handler'}` - Initial tests added for this feature Note that this is only adding support to Mn.Object and the Classes that inherit from it, not trying to add the same support to Backbone.View
1 parent 05a5d88 commit dd4bec8

File tree

9 files changed

+163
-3
lines changed

9 files changed

+163
-3
lines changed

SpecRunner.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
<script src="node_modules/jquery/dist/jquery.js"></script>
6060
<script src="node_modules/underscore/underscore.js"></script>
6161
<script src="node_modules/backbone/backbone.js"></script>
62-
<script src="node_modules/backbone.wreqr/lib/backbone.wreqr.js"></script>
6362
<script src="node_modules/backbone.babysitter/lib/backbone.babysitter.js"></script>
63+
<script src="node_modules/backbone.radio/build/backbone.radio.js"></script>
6464

6565

6666
<script>
@@ -69,6 +69,7 @@
6969
</script>
7070
<script src="src/trigger-method.js"></script>
7171
<script src="src/bind-entity-events.js"></script>
72+
<script src="src/radio-helpers.js"></script>
7273
<script src="src/dom-refresh.js"></script>
7374
<script src="src/helpers.js"></script>
7475
<script src="src/error.js"></script>
@@ -118,6 +119,7 @@
118119
<script src="test/unit/on-attach.spec.js"></script>
119120
<script src="test/unit/on-dom-refresh.spec.js"></script>
120121
<script src="test/unit/precompiled-template-rendering.spec.js"></script>
122+
<script src="test/unit/radio-helpers.spec.js"></script>
121123
<script src="test/unit/region-manager.spec.js"></script>
122124
<script src="test/unit/region.build-region.spec.js"></script>
123125
<script src="test/unit/region.spec.js"></script>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"github": "https://github.com/marionettejs/backbone.marionette",
4242
"dependencies": {
4343
"backbone.babysitter": "^0.1.0",
44+
"backbone.radio": "^0.9.0",
4445
"backbone": "1.0.0 - 1.1.2",
4546
"underscore": "1.4.4 - 1.6.0"
4647
},

src/build/bundled.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
// @include ../trigger-method.js
3737
// @include ../dom-refresh.js
3838
// @include ../bind-entity-events.js
39+
// @include ../radio-helpers.js
3940

4041
// @include ../error.js
4142
// @include ../object.js

src/build/core.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
(function(root, factory) {
22

33
if (typeof define === 'function' && define.amd) {
4-
define(['backbone', 'underscore', 'backbone.babysitter'], function(Backbone, _) {
4+
define(['backbone', 'underscore','backbone.radio', 'backbone.babysitter'],
5+
function(Backbone, _) {
56
return (root.Marionette = root.Mn = factory(root, Backbone, _));
67
});
78
} else if (typeof exports !== 'undefined') {
89
var Backbone = require('backbone');
910
var _ = require('underscore');
1011
var BabySitter = require('backbone.babysitter');
12+
var Radio = require('backbone.radio');
1113
module.exports = factory(root, Backbone, _);
1214
} else {
1315
root.Marionette = root.Mn = factory(root, root.Backbone, root._);
@@ -32,6 +34,7 @@
3234
// @include ../trigger-method.js
3335
// @include ../dom-refresh.js
3436
// @include ../bind-entity-events.js
37+
// @include ../radio-helpers.js
3538

3639
// @include ../error.js
3740
// @include ../object.js

src/object.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Object borrows many conventions and utilities from Backbone.
66
Marionette.Object = function(options) {
77
this.options = _.extend({}, _.result(this, 'options'), options);
8-
8+
Marionette.proxyRadioHandlers.apply(this);
99
this.initialize.apply(this, arguments);
1010
};
1111

@@ -23,6 +23,7 @@ _.extend(Marionette.Object.prototype, Backbone.Events, {
2323
destroy: function() {
2424
this.triggerMethod('before:destroy');
2525
this.triggerMethod('destroy');
26+
Marionette.unproxyRadioHandlers.apply(this);
2627
this.stopListening();
2728
},
2829

@@ -38,4 +39,5 @@ _.extend(Marionette.Object.prototype, Backbone.Events, {
3839

3940
// Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
4041
unbindEntityEvents: Marionette.proxyUnbindEntityEvents
42+
4143
});

src/radio-helpers.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
(function(Marionette, Radio) {
2+
3+
//Proxy Radio message handling to enable declarative interactions with radio channels
4+
var radioTypes = {
5+
'radioEvents' : {
6+
startMethod: 'on',
7+
stopMethod: 'off'
8+
},
9+
'radioCommands' : {
10+
startMethod: 'comply',
11+
stopMethod: 'stopComplying'
12+
},
13+
'radioRequests' : {
14+
startMethod: 'reply',
15+
stopMethod: 'stopReplying'
16+
}
17+
};
18+
19+
function proxyRadioHandlers() {
20+
unproxyRadioHandlers.apply(this);
21+
_.each(radioTypes, function(commands, radioType) {
22+
var hash = _.result(this, radioType);
23+
if (!hash) {
24+
return;
25+
}
26+
_.each(hash, function(handler, radioMessage) {
27+
if (!_.isFunction(handler)) {
28+
handler = this[handler];
29+
}
30+
if (!handler) {
31+
return;
32+
}
33+
var messageComponents = radioMessage.split(' '),
34+
channel = messageComponents[0],
35+
messageName = messageComponents[1];
36+
proxyRadioHandler.call(this,channel, radioType, messageName, handler);
37+
}, this);
38+
}, this);
39+
}
40+
41+
function proxyRadioHandler(channel, radioType, messageName, handler) {
42+
var method = radioTypes[radioType].startMethod;
43+
if(this._radioChannels) {
44+
if(!_.contains(this._radioChannels, channel)) {
45+
this._radioChannels.push(channel);
46+
}
47+
} else {
48+
this._radioChannels = [channel];
49+
}
50+
Radio[method](channel, messageName, handler, this);
51+
}
52+
53+
function unproxyRadioHandlers() {
54+
_.each(this._radioChannels, function(channel) {
55+
_.each(radioTypes,function(commands) {
56+
Radio[commands.stopMethod](channel, null, null, this);
57+
}, this);
58+
}, this);
59+
}
60+
61+
Marionette.proxyRadioHandlers = proxyRadioHandlers;
62+
Marionette.unproxyRadioHandlers = unproxyRadioHandlers;
63+
64+
})(Marionette,Backbone.Radio);

test/unit/object.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ describe('marionette object', function() {
4343
it('should maintain a reference to the options', function() {
4444
expect(this.object.options).to.deep.equal(this.options);
4545
});
46+
4647
});
4748

4849
describe('when destroying a object', function() {

test/unit/radio-helpers.spec.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
describe('Marionette radio helpers', function() {
2+
3+
describe('when creating a Marionette.Object', function() {
4+
5+
beforeEach(function() {
6+
this.clickStub1 = this.sinon.stub();
7+
this.clickStub2 = this.sinon.stub();
8+
this.clickStub3 = this.sinon.stub();
9+
this.Object = Marionette.Object.extend({
10+
radioEvents: {
11+
'foo bar' : this.clickStub1
12+
},
13+
radioCommands: {
14+
'bar foo' : this.clickStub2
15+
},
16+
radioRequests: {
17+
'foo bar' : 'baz'
18+
},
19+
20+
baz: this.clickStub3,
21+
22+
});
23+
this.object = new this.Object();
24+
Backbone.Radio.channel('foo').trigger('bar');
25+
Backbone.Radio.channel('foo').request('bar');
26+
Backbone.Radio.channel('bar').command('foo');
27+
28+
});
29+
30+
it('should support listening to radio events declaratively', function() {
31+
expect(this.clickStub1).to.have.been.calledOnce;
32+
});
33+
34+
it('should support complying to radio commands declaratively', function() {
35+
expect(this.clickStub2).to.have.been.calledOnce;
36+
});
37+
38+
it('should support replying to radio requests declaratively', function() {
39+
expect(this.clickStub3).to.have.been.calledOnce;
40+
});
41+
42+
43+
it('should unsubscribe events when the object is destroyed', function() {
44+
this.object.destroy();
45+
Backbone.Radio.channel('foo').trigger('bar');
46+
expect(this.clickStub1).to.have.been.calledOnce;
47+
});
48+
49+
it('should unsubscribe commands when the object is destroyed', function() {
50+
this.object.destroy();
51+
Backbone.Radio.channel('bar').command('foo');
52+
expect(this.clickStub2).to.have.been.calledOnce;
53+
});
54+
55+
it('should unsubscribe requests when the object is destroyed', function() {
56+
this.object.destroy();
57+
Backbone.Radio.channel('foo').request('bar');
58+
expect(this.clickStub3).to.have.been.calledOnce;
59+
});
60+
61+
it('shouldn\'t overunsubscribe events when the object is destroyed', function() {
62+
this.object2 = new this.Object();
63+
this.object.destroy();
64+
Backbone.Radio.channel('foo').trigger('bar');
65+
expect(this.clickStub1).to.have.been.calledTwice;
66+
});
67+
68+
it('shouldn\'t overunsubscribe commands when the object is destroyed', function() {
69+
this.object2 = new this.Object();
70+
this.object.destroy();
71+
Backbone.Radio.channel('bar').command('foo');
72+
expect(this.clickStub2).to.have.been.calledTwice;
73+
});
74+
75+
it('shouldn\'t overunsubscribe requests when the object is destroyed', function() {
76+
this.object2 = new this.Object();
77+
this.object.destroy();
78+
Backbone.Radio.channel('foo').request('bar');
79+
expect(this.clickStub3).to.have.been.calledTwice;
80+
});
81+
82+
});
83+
84+
});

test/unit/setup/node.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ global.Backbone = require('backbone');
3434
global.Backbone.$ = global.$;
3535
global.Marionette = Backbone.Marionette = {};
3636
require('backbone.babysitter');
37+
require('backbone.radio');
3738
global.slice = Array.prototype.slice;
3839
requireHelper('bind-entity-events');
40+
requireHelper('radio-helpers');
3941
requireHelper('trigger-method');
4042
requireHelper('helpers');
4143
requireHelper('dom-refresh');

0 commit comments

Comments
 (0)