Merge branch 'master' into gh-pages

This commit is contained in:
JC Brand 2013-04-19 22:21:39 +02:00
commit 419019c76f
5 changed files with 107 additions and 33 deletions

View File

@ -710,11 +710,13 @@
createChatRoom: function (ev) { createChatRoom: function (ev) {
ev.preventDefault(); ev.preventDefault();
var name, jid; var name, jid, input;
if (ev.type === 'click') { if (ev.type === 'click') {
jid = $(ev.target).attr('data-room-jid'); jid = $(ev.target).attr('data-room-jid');
} else { } else {
name = $(ev.target).find('input.new-chatroom-name').val().trim().toLowerCase(); input = this.$el.find('input.new-chatroom-name');
name = input.val().trim().toLowerCase();
input.val(''); // Clear the input
if (name) { if (name) {
jid = Strophe.escapeNode(name) + '@' + xmppchat.muc_domain; jid = Strophe.escapeNode(name) + '@' + xmppchat.muc_domain;
} else { } else {
@ -882,11 +884,11 @@
initialize: function () { initialize: function () {
xmppchat.connection.muc.join( xmppchat.connection.muc.join(
this.model.get('jid'), this.model.get('jid'),
this.model.get('nick'), this.model.get('nick'),
$.proxy(this.onChatRoomMessage, this), $.proxy(this.onChatRoomMessage, this),
$.proxy(this.onChatRoomPresence, this), $.proxy(this.onChatRoomPresence, this),
$.proxy(this.onChatRoomRoster, this)); $.proxy(this.onChatRoomRoster, this));
this.model.messages.on('add', this.showMessage, this); this.model.messages.on('add', this.showMessage, this);
@ -983,7 +985,7 @@
}, },
onChatRoomRoster: function (roster, room) { onChatRoomRoster: function (roster, room) {
// underscore size is needed because roster is on object // underscore size is needed because roster is an object
var controlboxview = xmppchat.chatboxesview.views.controlbox, var controlboxview = xmppchat.chatboxesview.views.controlbox,
roster_size = _.size(roster), roster_size = _.size(roster),
$participant_list = this.$el.find('.participant-list'), $participant_list = this.$el.find('.participant-list'),

View File

@ -16,7 +16,7 @@
<header class="inner"> <header class="inner">
<a id="forkme_banner" href="https://github.com/jcbrand/converse.js">View on GitHub</a> <a id="forkme_banner" href="https://github.com/jcbrand/converse.js">View on GitHub</a>
<h1 id="project_title">Converse.js</h1> <h1 id="project_title"><a href="http://conversejs.org">Converse.js</a></h1>
<h2 id="project_tagline">Browser-based Instant Messaging with Strophe.js and Backbone.js</h2> <h2 id="project_tagline">Browser-based Instant Messaging with Strophe.js and Backbone.js</h2>
<section id="downloads"> <section id="downloads">
@ -111,15 +111,14 @@
<h2>Licence</h2> <h2>Licence</h2>
<p><strong>Converse.js</strong> is released under both the <a href="http://opensource.org/licenses/mit-license.php" target="_blank">MIT</a> <p><strong>Converse.js</strong> is released under both the <a href="http://opensource.org/licenses/mit-license.php" target="_blank">MIT</a>
and <a href="http://opensource.org/licenses/gpl-license.php" target="_blank">GPL</a> licenses.</p> and <a href="http://opensource.org/licenses/GPL-2.0" target="_blank">GPL</a> licenses.</p>
</section> </section>
</div> </div>
<!-- FOOTER --> <!-- FOOTER -->
<div id="footer_wrap" class="outer"> <div id="footer_wrap" class="outer">
<footer class="inner"> <footer class="inner">
<p class="copyright">Converse.js maintained by <a href="https://github.com/jcbrand">jcbrand</a></p> <p class="copyright">Converse.js created by <a href="http://opkode.com" target="_blank">jcbrand</a></p>
<p>Published with <a href="http://pages.github.com">GitHub Pages</a></p>
</footer> </footer>
</div> </div>

View File

@ -24,7 +24,8 @@
this.bare_jid = 'dummy@localhost'; this.bare_jid = 'dummy@localhost';
mock_connection = { mock_connection = {
'muc': { 'muc': {
'listRooms': function () {} 'listRooms': function () {},
'join': function () {}
}, },
'jid': this.bare_jid, 'jid': this.bare_jid,
'addHandler': function (handler, ns, name, type, id, from, options) { 'addHandler': function (handler, ns, name, type, id, from, options) {
@ -57,35 +58,44 @@
this.onConnected(mock_connection); this.onConnected(mock_connection);
this.animate = false; // don't use animations this.animate = false; // don't use animations
// Variable declarations for specs
var open_controlbox;
describe("The Control Box", $.proxy(function () { describe("The Control Box", $.proxy(function () {
it("is not shown by default", $.proxy(function () { it("is not shown by default", $.proxy(function () {
expect(this.rosterview.$el.is(':visible')).toEqual(false); expect(this.rosterview.$el.is(':visible')).toEqual(false);
}, xmppchat)); }, xmppchat));
it("can be opened by clicking a DOM element with class 'toggle-online-users'", $.proxy(function () { open_controlbox = $.proxy(function () {
// This spec will only pass if the controlbox is not currently
// open yet.
expect($("div#controlbox").is(':visible')).toBe(false);
spyOn(this, 'toggleControlBox').andCallThrough(); spyOn(this, 'toggleControlBox').andCallThrough();
$('.toggle-online-users').click(); $('.toggle-online-users').click();
expect(this.toggleControlBox).toHaveBeenCalled(); expect(this.toggleControlBox).toHaveBeenCalled();
}, xmppchat)); expect($("div#controlbox").is(':visible')).toBe(true);
}, xmppchat);
it("can be opened by clicking a DOM element with class 'toggle-online-users'", open_controlbox);
describe("The Status Widget", $.proxy(function () { describe("The Status Widget", $.proxy(function () {
it("can be used to set the current user's chat status", $.proxy(function () { it("can be used to set the current user's chat status", $.proxy(function () {
var view = this.xmppstatusview; var view = this.xmppstatusview;
spyOn(view, 'toggleOptions').andCallThrough(); spyOn(view, 'toggleOptions').andCallThrough();
spyOn(view, 'setStatus').andCallThrough(); spyOn(view, 'setStatus').andCallThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
runs(function () {
view.$el.find('a.choose-xmpp-status').click(); view.$el.find('a.choose-xmpp-status').click();
expect(view.toggleOptions).toHaveBeenCalled(); expect(view.toggleOptions).toHaveBeenCalled();
expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(false); expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(false);
});
waits(250);
runs(function () { runs(function () {
spyOn(view, 'updateStatusUI').andCallThrough(); spyOn(view, 'updateStatusUI').andCallThrough();
view.initialize(); // Rebind events for spy view.initialize(); // Rebind events for spy
view.$el.find('.dropdown dd ul li a').first().click(); view.$el.find('.dropdown dd ul li a').first().click();
expect(view.setStatus).toHaveBeenCalled(); expect(view.setStatus).toHaveBeenCalled();
}); });
waits(100); waits(250);
runs($.proxy(function () { runs($.proxy(function () {
expect(view.updateStatusUI).toHaveBeenCalled(); expect(view.updateStatusUI).toHaveBeenCalled();
expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true); expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true);
@ -98,14 +108,16 @@
spyOn(view, 'setStatusMessage').andCallThrough(); spyOn(view, 'setStatusMessage').andCallThrough();
spyOn(view, 'renderStatusChangeForm').andCallThrough(); spyOn(view, 'renderStatusChangeForm').andCallThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
runs(function () { view.$el.find('a.change-xmpp-status-message').click();
view.$el.find('a.change-xmpp-status-message').click(); expect(view.renderStatusChangeForm).toHaveBeenCalled();
expect(view.renderStatusChangeForm).toHaveBeenCalled(); // The async testing here is used only to provide time for
// visual feedback
var msg = 'I am happy';
runs (function () {
view.$el.find('form input.custom-xmpp-status').val(msg);
}); });
waits(250); waits(250);
runs(function () { runs (function () {
var msg = 'I am happy';
view.$el.find('form input.custom-xmpp-status').val(msg);
view.$el.find('form#set-custom-xmpp-status').submit(); view.$el.find('form#set-custom-xmpp-status').submit();
expect(view.setStatusMessage).toHaveBeenCalled(); expect(view.setStatusMessage).toHaveBeenCalled();
expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true); expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true);
@ -450,6 +462,9 @@
// in localStorage either. // in localStorage either.
newchatboxes.onConnected(); newchatboxes.onConnected();
expect(newchatboxes.length).toEqual(0); expect(newchatboxes.length).toEqual(0);
// Lets open the controlbox again, purely for visual feedback
open_controlbox();
}, xmppchat)); }, xmppchat));
describe("A Chat Message", $.proxy(function () { describe("A Chat Message", $.proxy(function () {
@ -517,5 +532,63 @@
}, xmppchat)); }, xmppchat));
}, xmppchat)); }, xmppchat));
describe("The Controlbox Tabs", $.proxy(function () {
it("consist of two tabs, 'Contacts' and 'ChatRooms', of which 'Contacts' is by default visible", $.proxy(function () {
var cbview = this.chatboxesview.views.controlbox;
var $panels = cbview.$el.find('#controlbox-panes');
expect($panels.children().length).toBe(2);
expect($panels.children().first().attr('id')).toBe('users');
expect($panels.children().first().is(':visible')).toBe(true);
expect($panels.children().last().attr('id')).toBe('chatrooms');
expect($panels.children().last().is(':visible')).toBe(false);
}, xmppchat));
describe("The Chatrooms Panel", $.proxy(function () {
it("is opened by clicking the 'Chatrooms' tab", $.proxy(function () {
var cbview = this.chatboxesview.views.controlbox;
var $tabs = cbview.$el.find('#controlbox-tabs');
var $panels = cbview.$el.find('#controlbox-panes');
var $contacts = $panels.children().first();
var $chatrooms = $panels.children().last();
spyOn(cbview, 'switchTab').andCallThrough();
cbview.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
runs(function () {
$tabs.find('li').last().find('a').click(); // Clicks the chatrooms tab
});
waits(250);
runs(function () {
expect($contacts.is(':visible')).toBe(false);
expect($chatrooms.is(':visible')).toBe(true);
expect(cbview.switchTab).toHaveBeenCalled();
});
}, xmppchat));
it("contains a form through which a new chatroom can be created", $.proxy(function () {
var roomspanel = this.chatboxesview.views.controlbox.roomspanel;
var $input = roomspanel.$el.find('input.new-chatroom-name');
expect($input.length).toBe(1);
expect($('.chatroom').length).toBe(0); // There shouldn't be any chatrooms open currently
spyOn(roomspanel, 'createChatRoom').andCallThrough();
roomspanel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
runs(function () {
$input.val('Lounge');
});
waits('250');
runs(function () {
roomspanel.$el.find('form').submit();
expect(roomspanel.createChatRoom).toHaveBeenCalled();
});
waits('250');
runs($.proxy(function () {
expect($('.chatroom').length).toBe(1); // There should now be an open chatroom
}, xmppchat));
}, xmppchat));
}, xmppchat));
}, xmppchat));
}, xmppchat)); }, xmppchat));
})); }));

View File

@ -124,6 +124,10 @@ a {
-ms-transition: text-shadow 0.5s ease; -ms-transition: text-shadow 0.5s ease;
} }
h1 a {
color: white;
}
#main_content a:hover { #main_content a:hover {
color: #0069ba; color: #0069ba;
text-shadow: #5390c8 0px 0px 2px; text-shadow: #5390c8 0px 0px 2px;
@ -300,10 +304,6 @@ Full-Width Styles
background: linear-gradient(top, #373737, #212121); background: linear-gradient(top, #373737, #212121);
} }
#header_wrap .inner {
padding: 50px 10px 30px 10px;
}
#project_title { #project_title {
margin: 0; margin: 0;
color: #fff; color: #fff;

View File

@ -16,7 +16,7 @@
<body> <body>
<div id="header_wrap" class="outer"> <div id="header_wrap" class="outer">
<header class="inner"> <header class="inner">
<h1 id="project_title">Converse.js</h1> <h1 id="project_title"><a href="http://conversejs.org">Converse.js</a></h1>
<h2 id="project_tagline">Tests</h2> <h2 id="project_tagline">Tests</h2>
</header> </header>
</div> </div>