Bug 999480 - Panel to use a router & templated views, r=Standard8

This commit is contained in:
Nicolas Perriault 2014-05-29 21:13:45 +01:00
parent b148744fb0
commit c7eeff1458
3 changed files with 106 additions and 66 deletions

View File

@ -7,21 +7,42 @@
Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/Services.jsm");
var loop = loop || {}; var loop = loop || {};
loop.panel = (function(mozL10n) { loop.panel = (function(_, mozL10n) {
"use strict"; "use strict";
var baseServerUrl = Services.prefs.getCharPref("loop.server"), var baseServerUrl = Services.prefs.getCharPref("loop.server"),
panelView, sharedViews = loop.shared.views,
// aliasing translation function as __ for concision // aliasing translation function as __ for concision
__ = mozL10n.get; __ = mozL10n.get;
/** /**
* Panel view. * Panel router.
* * @type {loop.shared.router.BaseRouter}
* XXX view layout changes should be handled by a router really.
*/ */
var PanelView = Backbone.View.extend({ var router;
el: "#default-view",
/**
* Panel view.
*/
var PanelView = sharedViews.BaseView.extend({
template: _.template([
'<div class="description">',
' <p data-l10n-id="get_link_to_share"></p>',
'</div>',
'<div class="action">',
' <p class="invite">',
' <input type="text" name="caller" data-l10n-id="caller">',
' <a class="get-url btn btn-success disabled" href=""',
' data-l10n-id="get_a_call_url"></a>',
' </p>',
' <p class="result hide">',
' <input id="call-url" type="url" readonly>',
' <a class="go-back btn btn-info" href="" data-l10n-id="new_url"></a>',
' </p>',
'</div>',
].join("")),
className: "share generate-url",
events: { events: {
"keyup input[name=caller]": "changeButtonState", "keyup input[name=caller]": "changeButtonState",
@ -29,18 +50,23 @@ loop.panel = (function(mozL10n) {
"click a.go-back": "goBack" "click a.go-back": "goBack"
}, },
initialize: function() { initialize: function(options) {
options = options || {};
if (!options.notifier) {
throw new Error("missing required notifier");
}
this.notifier = options.notifier;
this.client = new loop.shared.Client({ this.client = new loop.shared.Client({
baseServerUrl: baseServerUrl baseServerUrl: baseServerUrl
}); });
this.notifier = new loop.shared.views.NotificationListView({ },
el: this.$(".messages")
}).render(); getNickname: function() {
return this.$("input[name=caller]").val();
}, },
getCallUrl: function(event) { getCallUrl: function(event) {
event.preventDefault(); event.preventDefault();
var nickname = this.$("input[name=caller]").val();
var callback = function(err, callUrl) { var callback = function(err, callUrl) {
if (err) { if (err) {
this.notifier.errorL10n("unable_retrieve_url"); this.notifier.errorL10n("unable_retrieve_url");
@ -49,7 +75,7 @@ loop.panel = (function(mozL10n) {
this.onCallUrlReceived(callUrl); this.onCallUrlReceived(callUrl);
}.bind(this); }.bind(this);
this.client.requestCallUrl(nickname, callback); this.client.requestCallUrl(this.getNickname(), callback);
}, },
goBack: function(event) { goBack: function(event) {
@ -76,16 +102,29 @@ loop.panel = (function(mozL10n) {
} }
}); });
var PanelRouter = loop.shared.router.BaseRouter.extend({
routes: {
"": "home"
},
home: function() {
this.loadView(new PanelView({notifier: this._notifier}));
}
});
/** /**
* Panel initialisation. * Panel initialisation.
*/ */
function init() { function init() {
panelView = new PanelView(); router = new PanelRouter({
panelView.render(); notifier: new sharedViews.NotificationListView({el: "#messages"})
});
Backbone.history.start();
} }
return { return {
init: init, init: init,
PanelView: PanelView PanelView: PanelView,
PanelRouter: PanelRouter
}; };
})(document.mozL10n); })(_, document.mozL10n);

View File

@ -9,29 +9,11 @@
<link rel="stylesheet" type="text/css" href="shared/css/common.css"> <link rel="stylesheet" type="text/css" href="shared/css/common.css">
<link rel="stylesheet" type="text/css" href="shared/css/panel.css"> <link rel="stylesheet" type="text/css" href="shared/css/panel.css">
</head> </head>
<body onload="loop.panel.init();"> <body class="panel" onload="loop.panel.init();">
<!-- XXX (n1k0): i10n tbd later as these are temporary texts. -->
<div id="default-view" class="share generate-url"> <div id="messages"></div>
<div class="description">
<p data-l10n-id="get_link_to_share"> <div id="main"></div>
Get a link to share with a friend to Video Chat.
</p>
</div>
<div class="action">
<div class="messages"></div>
<p class="invite">
<input type="text" name="caller" data-l10n-id="caller">
<a class="get-url btn btn-success disabled" href=""
data-l10n-id="get_a_call_url">Get a call url</a>
</p>
<p class="result hide">
<input id="call-url" type="url" readonly>
<a class="go-back btn btn-info" href="" data-l10n-id="new_url">
New url
</a>
</p>
</div>
</div>
<!-- XXX (adam): Should we import our own version of Webl10n? <!-- XXX (adam): Should we import our own version of Webl10n?
What we have here is a copy of the version from pdf.js What we have here is a copy of the version from pdf.js
@ -46,6 +28,7 @@
<script type="text/javascript" src="shared/libs/backbone-1.1.2.js"></script> <script type="text/javascript" src="shared/libs/backbone-1.1.2.js"></script>
<script type="text/javascript" src="shared/js/client.js"></script> <script type="text/javascript" src="shared/js/client.js"></script>
<script type="text/javascript" src="shared/js/models.js"></script> <script type="text/javascript" src="shared/js/models.js"></script>
<script type="text/javascript" src="shared/js/router.js"></script>
<script type="text/javascript" src="shared/js/views.js"></script> <script type="text/javascript" src="shared/js/views.js"></script>
<script type="text/javascript" src="js/panel.js"></script> <script type="text/javascript" src="js/panel.js"></script>
</body> </body>

View File

@ -9,7 +9,7 @@ var expect = chai.expect;
describe("loop.panel", function() { describe("loop.panel", function() {
"use strict"; "use strict";
var sandbox, fakeXHR, requests = []; var sandbox, notifier, fakeXHR, requests = [];
beforeEach(function() { beforeEach(function() {
sandbox = sinon.sandbox.create(); sandbox = sinon.sandbox.create();
@ -19,6 +19,14 @@ describe("loop.panel", function() {
fakeXHR.xhr.onCreate = function (xhr) { fakeXHR.xhr.onCreate = function (xhr) {
requests.push(xhr); requests.push(xhr);
}; };
notifier = {
clear: sandbox.spy(),
notify: sandbox.spy(),
warn: sandbox.spy(),
warnL10n: sandbox.spy(),
error: sandbox.spy(),
errorL10n: sandbox.spy()
};
}); });
afterEach(function() { afterEach(function() {
@ -26,34 +34,46 @@ describe("loop.panel", function() {
sandbox.restore(); sandbox.restore();
}); });
describe("loop.panel.PanelRouter", function() {
describe("#constructor", function() {
it("should require a notifier", function() {
expect(function() {
new loop.panel.PanelRouter();
}).to.Throw(Error, /missing required notifier/);
});
});
describe("constructed", function() {
var router;
beforeEach(function() {
router = new loop.panel.PanelRouter({notifier: notifier});
sandbox.stub(router, "loadView");
});
describe("#home", function() {
it("should load the PanelView", function() {
router.home();
sinon.assert.calledOnce(router.loadView);
sinon.assert.calledWithExactly(router.loadView,
sinon.match.instanceOf(loop.panel.PanelView));
});
});
});
});
describe("loop.panel.PanelView", function() { describe("loop.panel.PanelView", function() {
beforeEach(function() { beforeEach(function() {
$("#fixtures").append([ $("#fixtures").append('<div id="messages"></div><div id="main"></div>');
'<div id="default-view" class="share generate-url">',
' <div class="description">',
' <p>Get a link to share with a friend to Video Chat.</p>',
' </div>',
' <div class="action">',
' <div class="messages"></div>',
' <p class="invite">',
' <input type="text" placeholder="Nickname of the future caller"',
' name="caller" value="foo"/>',
' <a class="get-url" href="">Get a call url</a>',
' </p>',
' <p class="result hide">',
' <input id="call-url" type="url" readonly>',
' <a class="get-url" href="">Renew</a>',
' </p>',
' </div>',
'</div>'
].join(""));
}); });
describe("#getCallUrl", function() { describe("#getCallUrl", function() {
it("should request a call url to the server", function() { it("should request a call url to the server", function() {
var requestCallUrl = sandbox.stub(loop.shared.Client.prototype, var requestCallUrl = sandbox.stub(loop.shared.Client.prototype,
"requestCallUrl"); "requestCallUrl");
var view = new loop.panel.PanelView(); var view = new loop.panel.PanelView({notifier: notifier});
sandbox.stub(view, "getNickname").returns("foo");
view.getCallUrl({preventDefault: sandbox.spy()}); view.getCallUrl({preventDefault: sandbox.spy()});
@ -66,8 +86,7 @@ describe("loop.panel", function() {
loop.shared.Client.prototype, "requestCallUrl", function(_, cb) { loop.shared.Client.prototype, "requestCallUrl", function(_, cb) {
cb("fake error"); cb("fake error");
}); });
var view = new loop.panel.PanelView(); var view = new loop.panel.PanelView({notifier: notifier});
sandbox.stub(view.notifier, "errorL10n");
view.getCallUrl({preventDefault: sandbox.spy()}); view.getCallUrl({preventDefault: sandbox.spy()});
@ -79,7 +98,7 @@ describe("loop.panel", function() {
describe("#onCallUrlReceived", function() { describe("#onCallUrlReceived", function() {
it("should update the text field with the call url", function() { it("should update the text field with the call url", function() {
var view = new loop.panel.PanelView(); var view = new loop.panel.PanelView({notifier: notifier});
view.render(); view.render();
view.onCallUrlReceived("http://call.me/"); view.onCallUrlReceived("http://call.me/");
@ -88,8 +107,7 @@ describe("loop.panel", function() {
}); });
it("should reset all pending notifications", function() { it("should reset all pending notifications", function() {
var view = new loop.panel.PanelView().render(); var view = new loop.panel.PanelView({notifier: notifier}).render();
sandbox.stub(view.notifier, "clear");
view.onCallUrlReceived("http://call.me/"); view.onCallUrlReceived("http://call.me/");