Commit 0d9fa4a9 authored by JC Brand's avatar JC Brand

Merge branch 'master' into gh-pages

parents 419019c7 93d31f26
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
converse.js converse.js
=========== ===========
Converse.js_ implements an XMPP_ based instant messaging client in the browser. Converse.js_ is a web based `XMPP/Jabber`_ instant messaging client.
It is used by collective.xmpp.chat_, which is a Plone_ instant messaging add-on. It is used by collective.xmpp.chat_, which is a Plone_ instant messaging add-on.
The ultimate goal is to enable anyone to add chat functionality to their websites, regardless of the backend. The ultimate goal is to enable anyone to add chat functionality to their websites, independent of any backend.
This is currently possible, except for adding new contacts, which still makes an XHR call to the (Plone) backend to fetch user info. You will however need an XMPP server to connect to, either your own, or a public one.
-------- --------
Features Features
...@@ -54,7 +54,7 @@ Licence ...@@ -54,7 +54,7 @@ Licence
.. _require.js: http:/requirejs.org .. _require.js: http:/requirejs.org
.. _collective.xmpp.chat: http://github.com/collective/collective.xmpp.chat .. _collective.xmpp.chat: http://github.com/collective/collective.xmpp.chat
.. _Plone: http://plone.org .. _Plone: http://plone.org
.. _XMPP: http://xmpp.org .. _`XMPP/Jabber`: http://xmpp.org
.. _MIT: http://opensource.org/licenses/mit-license.php .. _MIT: http://opensource.org/licenses/mit-license.php
.. _GPL: http://opensource.org/licenses/gpl-license.php .. _GPL: http://opensource.org/licenses/gpl-license.php
.. _here: http://opkode.com/media/blog/instant-messaging-for-plone-with-javascript-and-xmpp .. _here: http://opkode.com/media/blog/instant-messaging-for-plone-with-javascript-and-xmpp
......
...@@ -182,6 +182,10 @@ div.delayed .chat-message-me { ...@@ -182,6 +182,10 @@ div.delayed .chat-message-me {
color: #7EABBB; color: #7EABBB;
} }
input.error {
border: 1px solid red;
}
.chat-message-error { .chat-message-error {
color:#76797C; color:#76797C;
font-size:90%; font-size:90%;
...@@ -234,9 +238,8 @@ a.subscribe-to-user { ...@@ -234,9 +238,8 @@ a.subscribe-to-user {
font-weight: bold; font-weight: bold;
} }
dl.add-xmpp-contact { dl.add-converse-contact {
margin: 0 0 0 0.5em; margin: 0 0 0 0.5em;
padding-top: 3px;
z-index: 21; z-index: 21;
background: url('images/add_icon.png') no-repeat 3px; background: url('images/add_icon.png') no-repeat 3px;
} }
...@@ -245,8 +248,13 @@ dt#xmpp-contact-search { ...@@ -245,8 +248,13 @@ dt#xmpp-contact-search {
padding-top: 3px; padding-top: 3px;
} }
.fancy-dropdown {
border:1px solid #ddd;
height: 22px;
}
.fancy-dropdown a.choose-xmpp-status, .fancy-dropdown a.choose-xmpp-status,
.fancy-dropdown a.add-xmpp-contact { .fancy-dropdown a.toggle-xmpp-contact-form {
text-shadow: 0 1px 0 rgba(250, 250, 250, 1); text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
padding-left: 1.5em; padding-left: 1.5em;
width: 140px; width: 140px;
...@@ -272,7 +280,7 @@ dt#xmpp-contact-search { ...@@ -272,7 +280,7 @@ dt#xmpp-contact-search {
ul#found-users { ul#found-users {
padding: 10px 0 5px 5px; padding: 10px 0 5px 5px;
border: 0; border: 0;
} }
form.search-xmpp-contact { form.search-xmpp-contact {
...@@ -283,7 +291,7 @@ form.search-xmpp-contact { ...@@ -283,7 +291,7 @@ form.search-xmpp-contact {
} }
form.search-xmpp-contact input { form.search-xmpp-contact input {
width: 9em; width: 8em;
} }
.oc-chat-head { .oc-chat-head {
...@@ -340,42 +348,42 @@ form.search-xmpp-contact input { ...@@ -340,42 +348,42 @@ form.search-xmpp-contact input {
padding-top: 0.5em; padding-top: 0.5em;
} }
#xmppchat-roster dd.odd { #converse-roster dd.odd {
background-color: #DCEAC5; /* Make this difference */ background-color: #DCEAC5; /* Make this difference */
} }
#xmppchat-roster dd.current-xmpp-contact { #converse-roster dd.current-xmpp-contact {
clear: both; clear: both;
} }
#xmppchat-roster dd.current-xmpp-contact, #converse-roster dd.current-xmpp-contact,
#xmppchat-roster dd.current-xmpp-contact:hover { #converse-roster dd.current-xmpp-contact:hover {
background: url(images/user_online_panel.png) no-repeat 5px 2px; background: url(images/user_online_panel.png) no-repeat 5px 2px;
} }
#xmppchat-roster dd.current-xmpp-contact.offline:hover, #converse-roster dd.current-xmpp-contact.offline:hover,
#xmppchat-roster dd.current-xmpp-contact.unavailable:hover, #converse-roster dd.current-xmpp-contact.unavailable:hover,
#xmppchat-roster dd.current-xmpp-contact.offline, #converse-roster dd.current-xmpp-contact.offline,
#xmppchat-roster dd.current-xmpp-contact.unavailable { #converse-roster dd.current-xmpp-contact.unavailable {
background: url(images/user_offline_panel.png) no-repeat 5px 2px; background: url(images/user_offline_panel.png) no-repeat 5px 2px;
} }
#xmppchat-roster dd.current-xmpp-contact.dnd, #converse-roster dd.current-xmpp-contact.dnd,
#xmppchat-roster dd.current-xmpp-contact.dnd:hover { #converse-roster dd.current-xmpp-contact.dnd:hover {
background: url(images/user_busy_panel.png) no-repeat 5px 2px; background: url(images/user_busy_panel.png) no-repeat 5px 2px;
} }
#xmppchat-roster dd.current-xmpp-contact.away, #converse-roster dd.current-xmpp-contact.away,
#xmppchat-roster dd.current-xmpp-contact.away:hover { #converse-roster dd.current-xmpp-contact.away:hover {
background: url(images/user_away_panel.png) no-repeat 5px 2px; background: url(images/user_away_panel.png) no-repeat 5px 2px;
} }
#xmppchat-roster dd.requesting-xmpp-contact button{ #converse-roster dd.requesting-xmpp-contact button{
margin-left: 0.5em; margin-left: 0.5em;
} }
#xmppchat-roster dd a, #converse-roster dd a,
#xmppchat-roster dd span { #converse-roster dd span {
text-shadow: 0 1px 0 rgba(250, 250, 250, 1); text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
...@@ -383,12 +391,12 @@ form.search-xmpp-contact input { ...@@ -383,12 +391,12 @@ form.search-xmpp-contact input {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#xmppchat-roster dd a { #converse-roster dd a {
margin-left: 1.5em; margin-left: 1.5em;
width: 113px; width: 113px;
} }
#xmppchat-roster dd span { #converse-roster dd span {
width: 125px; width: 125px;
} }
...@@ -396,7 +404,7 @@ form.search-xmpp-contact input { ...@@ -396,7 +404,7 @@ form.search-xmpp-contact input {
border: none; border: none;
} }
#xmppchat-roster { #converse-roster {
height: 200px; height: 200px;
overflow-y: scroll; overflow-y: scroll;
width: 100%; width: 100%;
...@@ -408,7 +416,7 @@ form.search-xmpp-contact input { ...@@ -408,7 +416,7 @@ form.search-xmpp-contact input {
} }
#available-chatrooms dt, #available-chatrooms dt,
#xmppchat-roster dt { #converse-roster dt {
font-weight: normal; font-weight: normal;
display: none; display: none;
font-size: 13px; font-size: 13px;
...@@ -428,7 +436,7 @@ form.search-xmpp-contact input { ...@@ -428,7 +436,7 @@ form.search-xmpp-contact input {
dd.available-chatroom, dd.available-chatroom,
#xmppchat-roster dd { #converse-roster dd {
font-weight: bold; font-weight: bold;
border: none; border: none;
display: block; display: block;
...@@ -437,7 +445,7 @@ dd.available-chatroom, ...@@ -437,7 +445,7 @@ dd.available-chatroom,
text-shadow: 0 1px 0 rgba(250, 250, 250, 1); text-shadow: 0 1px 0 rgba(250, 250, 250, 1);
} }
#xmppchat-roster dd a.remove-xmpp-contact { #converse-roster dd a.remove-xmpp-contact {
background: url('images/delete_icon.png') no-repeat right top; background: url('images/delete_icon.png') no-repeat right top;
padding: 0 1em 1em 0; padding: 0 1em 1em 0;
float: right; float: right;
...@@ -494,12 +502,12 @@ div#controlbox-panes { ...@@ -494,12 +502,12 @@ div#controlbox-panes {
width: 199px; width: 199px;
} }
form#xmppchat-login { form#converse-login {
background: white; background: white;
padding: 2em 0 0.3em 0.5em; padding: 2em 0 0.3em 0.5em;
} }
form#xmppchat-login input { form#converse-login input {
display: block; display: block;
} }
...@@ -599,17 +607,12 @@ form.sendXMPPMessage { ...@@ -599,17 +607,12 @@ form.sendXMPPMessage {
form#set-custom-xmpp-status { form#set-custom-xmpp-status {
float: left; float: left;
padding: 0; padding: 0;
background: none;
} }
#set-custom-xmpp-status button { #set-custom-xmpp-status button {
padding: 1px 2px 1px 1px; padding: 1px 2px 1px 1px;
} }
input.custom-xmpp-status {
width: 138px;
}
/* status dropdown styles */ /* status dropdown styles */
dl.dropdown { dl.dropdown {
margin-right: 0.5em; margin-right: 0.5em;
...@@ -622,9 +625,17 @@ div.xmpp-status { ...@@ -622,9 +625,17 @@ div.xmpp-status {
padding: 3px; padding: 3px;
} }
.fancy-dropdown { input.custom-xmpp-status {
border:1px solid #ddd; width: 138px;
height: 22px; }
form.add-xmpp-contact {
background: white;
padding: 5px;
}
form.add-xmpp-contact input {
width: 125px;
} }
.dropdown dt a span { .dropdown dt a span {
......
...@@ -79,12 +79,12 @@ ...@@ -79,12 +79,12 @@
evaluate : /\{\[([\s\S]+?)\]\}/g, evaluate : /\{\[([\s\S]+?)\]\}/g,
interpolate : /\{\{([\s\S]+?)\}\}/g interpolate : /\{\{([\s\S]+?)\}\}/g
}; };
root.xmppchat = factory(jQuery, _, console || {log: function(){}}); root.converse = factory(jQuery, _, console || {log: function(){}});
} }
}(this, function ($, _, console) { }(this, function ($, _, console) {
var xmppchat = {}; var converse = {};
xmppchat.msg_counter = 0; converse.msg_counter = 0;
var strinclude = function(str, needle){ var strinclude = function(str, needle){
if (needle === '') { return true; } if (needle === '') { return true; }
...@@ -92,13 +92,13 @@ ...@@ -92,13 +92,13 @@
return String(str).indexOf(needle) !== -1; return String(str).indexOf(needle) !== -1;
}; };
xmppchat.autoLink = function (text) { converse.autoLink = function (text) {
// Convert URLs into hyperlinks // Convert URLs into hyperlinks
var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g; var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
return text.replace(re, '<a target="_blank" href="$1">$1</a>'); return text.replace(re, '<a target="_blank" href="$1">$1</a>');
}; };
xmppchat.toISOString = function (date) { converse.toISOString = function (date) {
var pad; var pad;
if (typeof date.toISOString !== 'undefined') { if (typeof date.toISOString !== 'undefined') {
return date.toISOString(); return date.toISOString();
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
} }
}; };
xmppchat.parseISO8601 = function (datestr) { converse.parseISO8601 = function (datestr) {
/* Parses string formatted as 2013-02-14T11:27:08.268Z to a Date obj. /* Parses string formatted as 2013-02-14T11:27:08.268Z to a Date obj.
*/ */
    var numericKeys = [1, 4, 5, 6, 7, 10, 11],     var numericKeys = [1, 4, 5, 6, 7, 10, 11],
...@@ -140,7 +140,7 @@ ...@@ -140,7 +140,7 @@
return new Date(Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7])); return new Date(Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]));
}; };
xmppchat.updateMsgCounter = function () { converse.updateMsgCounter = function () {
if (this.msg_counter > 0) { if (this.msg_counter > 0) {
if (document.title.search(/^Messages \(\d+\) /) == -1) { if (document.title.search(/^Messages \(\d+\) /) == -1) {
document.title = "Messages (" + this.msg_counter + ") " + document.title; document.title = "Messages (" + this.msg_counter + ") " + document.title;
...@@ -154,17 +154,17 @@ ...@@ -154,17 +154,17 @@
} }
}; };
xmppchat.incrementMsgCounter = function () { converse.incrementMsgCounter = function () {
this.msg_counter += 1; this.msg_counter += 1;
this.updateMsgCounter(); this.updateMsgCounter();
}; };
xmppchat.clearMsgCounter = function () { converse.clearMsgCounter = function () {
this.msg_counter = 0; this.msg_counter = 0;
this.updateMsgCounter(); this.updateMsgCounter();
}; };
xmppchat.collections = { converse.collections = {
/* FIXME: XEP-0136 specifies 'urn:xmpp:archive' but the mod_archive_odbc /* FIXME: XEP-0136 specifies 'urn:xmpp:archive' but the mod_archive_odbc
* add-on for ejabberd wants the URL below. This might break for other * add-on for ejabberd wants the URL below. This might break for other
* Jabber servers. * Jabber servers.
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
'URI': 'http://www.xmpp.org/extensions/xep-0136.html#ns' 'URI': 'http://www.xmpp.org/extensions/xep-0136.html#ns'
}; };
xmppchat.collections.getLastCollection = function (jid, callback) { converse.collections.getLastCollection = function (jid, callback) {
var bare_jid = Strophe.getBareJidFromJid(jid), var bare_jid = Strophe.getBareJidFromJid(jid),
iq = $iq({'type':'get'}) iq = $iq({'type':'get'})
.c('list', {'xmlns': this.URI, .c('list', {'xmlns': this.URI,
...@@ -183,14 +183,14 @@ ...@@ -183,14 +183,14 @@
.c('max') .c('max')
.t('1'); .t('1');
xmppchat.connection.sendIQ(iq, converse.connection.sendIQ(iq,
callback, callback,
function () { function () {
console.log('Error while retrieving collections'); console.log('Error while retrieving collections');
}); });
}; };
xmppchat.collections.getLastMessages = function (jid, callback) { converse.collections.getLastMessages = function (jid, callback) {
var that = this; var that = this;
this.getLastCollection(jid, function (result) { this.getLastCollection(jid, function (result) {
// Retrieve the last page of a collection (max 30 elements). // Retrieve the last page of a collection (max 30 elements).
...@@ -205,20 +205,20 @@ ...@@ -205,20 +205,20 @@
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'}) .c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('max') .c('max')
.t('30'); .t('30');
xmppchat.connection.sendIQ(iq, callback); converse.connection.sendIQ(iq, callback);
}); });
}; };
xmppchat.Message = Backbone.Model.extend(); converse.Message = Backbone.Model.extend();
xmppchat.Messages = Backbone.Collection.extend({ converse.Messages = Backbone.Collection.extend({
model: xmppchat.Message model: converse.Message
}); });
xmppchat.ChatBox = Backbone.Model.extend({ converse.ChatBox = Backbone.Model.extend({
initialize: function () { initialize: function () {
if (this.get('box_id') !== 'controlbox') { if (this.get('box_id') !== 'controlbox') {
this.messages = new xmppchat.Messages(); this.messages = new converse.Messages();
this.messages.localStorage = new Backbone.LocalStorage( this.messages.localStorage = new Backbone.LocalStorage(
hex_sha1('converse.messages'+this.get('jid'))); hex_sha1('converse.messages'+this.get('jid')));
this.set({ this.set({
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
messageReceived: function (message) { messageReceived: function (message) {
var $message = $(message), var $message = $(message),
body = xmppchat.autoLink($message.children('body').text()), body = converse.autoLink($message.children('body').text()),
from = Strophe.getBareJidFromJid($message.attr('from')), from = Strophe.getBareJidFromJid($message.attr('from')),
composing = $message.find('composing'), composing = $message.find('composing'),
delayed = $message.find('delay').length > 0, delayed = $message.find('delay').length > 0,
...@@ -247,7 +247,7 @@ ...@@ -247,7 +247,7 @@
fullname: fullname, fullname: fullname,
sender: 'them', sender: 'them',
delayed: delayed, delayed: delayed,
time: xmppchat.toISOString(new Date()), time: converse.toISOString(new Date()),
composing: composing.length composing: composing.length
}); });
} }
...@@ -256,9 +256,9 @@ ...@@ -256,9 +256,9 @@
stamp = $message.find('delay').attr('stamp'); stamp = $message.find('delay').attr('stamp');
time = stamp; time = stamp;
} else { } else {
time = xmppchat.toISOString(new Date()); time = converse.toISOString(new Date());
} }
if (from == xmppchat.bare_jid) { if (from == converse.bare_jid) {
fullname = 'me'; fullname = 'me';
sender = 'me'; sender = 'me';
} else { } else {
...@@ -275,7 +275,7 @@ ...@@ -275,7 +275,7 @@
} }
}); });
xmppchat.ChatBoxView = Backbone.View.extend({ converse.ChatBoxView = Backbone.View.extend({
length: 200, length: 200,
tagName: 'div', tagName: 'div',
className: 'chatbox', className: 'chatbox',
...@@ -311,7 +311,7 @@ ...@@ -311,7 +311,7 @@
showMessage: function (message) { showMessage: function (message) {
var time = message.get('time'), var time = message.get('time'),
times = this.model.messages.pluck('time'), times = this.model.messages.pluck('time'),
this_date = xmppchat.parseISO8601(time), this_date = converse.parseISO8601(time),
$chat_content = this.$el.find('.chat-content'), $chat_content = this.$el.find('.chat-content'),
previous_message, idx, prev_date, isodate; previous_message, idx, prev_date, isodate;
...@@ -320,10 +320,10 @@ ...@@ -320,10 +320,10 @@
idx = _.indexOf(times, time)-1; idx = _.indexOf(times, time)-1;
if (idx >= 0) { if (idx >= 0) {
previous_message = this.model.messages.at(idx); previous_message = this.model.messages.at(idx);
prev_date = xmppchat.parseISO8601(previous_message.get('time')); prev_date = converse.parseISO8601(previous_message.get('time'));
isodate = new Date(this_date.getTime()); isodate = new Date(this_date.getTime());
isodate.setUTCHours(0,0,0,0); isodate.setUTCHours(0,0,0,0);
isodate = xmppchat.toISOString(isodate); isodate = converse.toISOString(isodate);
if (this.isDifferentDay(prev_date, this_date)) { if (this.isDifferentDay(prev_date, this_date)) {
$chat_content.append(this.new_day_template({ $chat_content.append(this.new_day_template({
isodate: isodate, isodate: isodate,
...@@ -331,7 +331,7 @@ ...@@ -331,7 +331,7 @@
})); }));
} }
} }
if (xmppchat.xmppstatus.get('status') === 'offline') { if (converse.xmppstatus.get('status') === 'offline') {
// only update the UI if the user is not offline // only update the UI if the user is not offline
return; return;
} }
...@@ -350,15 +350,15 @@ ...@@ -350,15 +350,15 @@
})); }));
} }
if (message.get('sender') != 'me') { if (message.get('sender') != 'me') {
xmppchat.incrementMsgCounter(); converse.incrementMsgCounter();
} }
this.scrollDown(); this.scrollDown();
}, },
isDifferentDay: function (prev_date, next_date) { isDifferentDay: function (prev_date, next_date) {
return ( return (
(next_date.getDate() != prev_date.getDate()) || (next_date.getDate() != prev_date.getDate()) ||
(next_date.getFullYear() != prev_date.getFullYear()) || (next_date.getFullYear() != prev_date.getFullYear()) ||
(next_date.getMonth() != prev_date.getMonth())); (next_date.getMonth() != prev_date.getMonth()));
}, },
...@@ -396,23 +396,23 @@ ...@@ -396,23 +396,23 @@
} }
} }
var message = $msg({from: xmppchat.bare_jid, to: bare_jid, type: 'chat', id: timestamp}) var message = $msg({from: converse.bare_jid, to: bare_jid, type: 'chat', id: timestamp})
.c('body').t(text).up() .c('body').t(text).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}); .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'});
// Forward the message, so that other connected resources are also aware of it. // Forward the message, so that other connected resources are also aware of it.
// TODO: Forward the message only to other connected resources (inside the browser) // TODO: Forward the message only to other connected resources (inside the browser)
var forwarded = $msg({to:xmppchat.bare_jid, type:'chat', id:timestamp}) var forwarded = $msg({to:converse.bare_jid, type:'chat', id:timestamp})
.c('forwarded', {xmlns:'urn:xmpp:forward:0'}) .c('forwarded', {xmlns:'urn:xmpp:forward:0'})
.c('delay', {xmns:'urn:xmpp:delay',stamp:timestamp}).up() .c('delay', {xmns:'urn:xmpp:delay',stamp:timestamp}).up()
.cnode(message.tree()); .cnode(message.tree());
xmppchat.connection.send(message); converse.connection.send(message);
xmppchat.connection.send(forwarded); converse.connection.send(forwarded);
// Add the new message // Add the new message
this.model.messages.create({ this.model.messages.create({
fullname: 'me', fullname: 'me',
sender: 'me', sender: 'me',
time: xmppchat.toISOString(new Date()), time: converse.toISOString(new Date()),
message: text message: text
}); });
}, },
...@@ -444,7 +444,7 @@ ...@@ -444,7 +444,7 @@
// starts with forward-slash. // starts with forward-slash.
notify = $msg({'to':this.model.get('jid'), 'type': 'chat'}) notify = $msg({'to':this.model.get('jid'), 'type': 'chat'})
.c('composing', {'xmlns':'http://jabber.org/protocol/chatstates'}); .c('composing', {'xmlns':'http://jabber.org/protocol/chatstates'});
xmppchat.connection.send(notify); converse.connection.send(notify);
} }
this.$el.data('composing', true); this.$el.data('composing', true);
} }
...@@ -476,7 +476,7 @@ ...@@ -476,7 +476,7 @@
}, },
closeChat: function () { closeChat: function () {
if (xmppchat.connection) { if (converse.connection) {
this.model.destroy(); this.model.destroy();
} else { } else {
this.model.trigger('hide'); this.model.trigger('hide');
...@@ -489,12 +489,12 @@ ...@@ -489,12 +489,12 @@
this.model.on('destroy', this.hide, this); this.model.on('destroy', this.hide, this);
this.model.on('change', this.onChange, this); this.model.on('change', this.onChange, this);
this.$el.appendTo(xmppchat.chatboxesview.$el); this.$el.appendTo(converse.chatboxesview.$el);
this.render().show().model.messages.fetch({add: true}); this.render().show().model.messages.fetch({add: true});
if (this.model.get('status')) { if (this.model.get('status')) {
this.showStatusMessage(this.model.get('status')); this.showStatusMessage(this.model.get('status'));
} }
xmppchat.clearMsgCounter(); converse.clearMsgCounter();
}, },
template: _.template( template: _.template(
...@@ -537,7 +537,7 @@ ...@@ -537,7 +537,7 @@
}, },
hide: function () { hide: function () {
if (xmppchat.animate) { if (converse.animate) {
this.$el.hide('fast'); this.$el.hide('fast');
} else { } else {
this.$el.hide(); this.$el.hide();
...@@ -548,12 +548,12 @@ ...@@ -548,12 +548,12 @@
if (this.$el.is(':visible') && this.$el.css('opacity') == "1") { if (this.$el.is(':visible') && this.$el.css('opacity') == "1") {
return this.focus(); return this.focus();
} }
if (xmppchat.animate) { if (converse.animate) {
this.$el.css({'opacity': 0, 'display': 'inline'}).animate({opacity: '1'}, 200); this.$el.css({'opacity': 0, 'display': 'inline'}).animate({opacity: '1'}, 200);
} else { } else {
this.$el.css({'opacity': 1, 'display': 'inline'}); this.$el.css({'opacity': 1, 'display': 'inline'});
} }
if (xmppchat.connection) { if (converse.connection) {
// Without a connection, we haven't yet initialized // Without a connection, we haven't yet initialized
// localstorage // localstorage
this.model.save(); this.model.save();
...@@ -568,14 +568,15 @@ ...@@ -568,14 +568,15 @@
} }
}); });
xmppchat.ContactsPanel = Backbone.View.extend({ converse.ContactsPanel = Backbone.View.extend({
tagName: 'div', tagName: 'div',
className: 'oc-chat-content', className: 'oc-chat-content',
id: 'users', id: 'users',
events: { events: {
'click a.add-xmpp-contact': 'toggleContactForm', 'click a.toggle-xmpp-contact-form': 'toggleContactForm',
'submit form.add-xmpp-contact': 'addContactFromForm',
'submit form.search-xmpp-contact': 'searchContacts', 'submit form.search-xmpp-contact': 'searchContacts',
'click a.subscribe-to-user': 'subscribeToContact' 'click a.subscribe-to-user': 'addContactFromList'
}, },
tab_template: _.template('<li><a class="s current" href="#users">Contacts</a></li>'), tab_template: _.template('<li><a class="s current" href="#users">Contacts</a></li>'),
...@@ -590,66 +591,109 @@ ...@@ -590,66 +591,109 @@
'</select>'+ '</select>'+
'</span>'+ '</span>'+
'</form>'+ '</form>'+
'<dl class="add-xmpp-contact dropdown">' + '<dl class="add-converse-contact dropdown">' +
'<dt id="xmpp-contact-search" class="fancy-dropdown">' + '<dt id="xmpp-contact-search" class="fancy-dropdown">' +
'<a class="add-xmpp-contact" href="#" title="Click to search for new users to add as chat contacts">Add a contact</a>' + '<a class="toggle-xmpp-contact-form" href="#" title="Click to add new chat contacts">Add a contact</a>' +
'</dt>' + '</dt>' +
'<dd class="search-xmpp" style="display:none"><ul>' + '<dd class="search-xmpp" style="display:none"><ul></ul></dd>' +
'</dl>'
),
add_contact_template: _.template(
'<form class="add-xmpp-contact">' +
'<input type="text" name="identifier" class="username" placeholder="Contact name"/>' +
'<button type="submit">Add</button>' +
'</form>'),
search_contact_template: _.template(
'<form class="search-xmpp-contact">' + '<form class="search-xmpp-contact">' +
'<input type="text" name="identifier" class="username" placeholder="Contact name"/>' + '<input type="text" name="identifier" class="username" placeholder="Contact name"/>' +
'<button type="submit">Search</button>' + '<button type="submit">Search</button>' +
'<ul id="found-users"></ul>' + '<ul id="found-users"></ul>' +
'</form>' + '</form>'),
'</ul></dd>' +
'</dl>'
),
render: function () { render: function () {
var markup;
this.$parent.find('#controlbox-tabs').append(this.tab_template()); this.$parent.find('#controlbox-tabs').append(this.tab_template());
this.$parent.find('#controlbox-panes').append(this.$el.html(this.template())); this.$parent.find('#controlbox-panes').append(this.$el.html(this.template()));
if (converse.xhr_user_search) {
markup = this.search_contact_template();
} else {
markup = this.add_contact_template();
}
this.$el.find('.search-xmpp ul').append(markup);
return this; return this;
}, },
toggleContactForm: function (ev) { toggleContactForm: function (ev) {
ev.preventDefault(); ev.preventDefault();
this.$el.find('.search-xmpp').toggle().find('input.username').focus(); this.$el.find('.search-xmpp').toggle('fast', function () {
if ($(this).is(':visible')) {
$(this).find('input.username').focus();
}
});
}, },
searchContacts: function (ev) { searchContacts: function (ev) {
ev.preventDefault(); ev.preventDefault();
$.getJSON(portal_url + "/search-users?q=" + $(ev.target).find('input.username').val(), function (data) { $.getJSON(portal_url + "/search-users?q=" + $(ev.target).find('input.username').val(), function (data) {
var $results_el = $('#found-users'); var $results_el = $('#found-users');
$(data).each(function (idx, obj) { $(data).each(function (idx, obj) {
if ($results_el.children().length) { if ($results_el.children().length) {
$results_el.empty(); $results_el.empty();
} }
$results_el.append( $results_el.append(
$('<li></li>') $('<li></li>')
.attr('id', 'found-users-'+obj.id) .attr('id', 'found-users-'+obj.id)
.append( .append(
$('<a class="subscribe-to-user" href="#" title="Click to add as a chat contact"></a>') $('<a class="subscribe-to-user" href="#" title="Click to add as a chat contact"></a>')
.attr('data-recipient', Strophe.escapeNode(obj.id)+'@'+xmppchat.domain) .attr('data-recipient', Strophe.escapeNode(obj.id)+'@'+converse.domain)
.text(obj.fullname) .text(obj.fullname)
) )
); );
}); });
}); });
}, },
addContactFromForm: function (ev) {
ev.preventDefault();
var $input = $(ev.target).find('input');
var jid = $input.val();
if (! jid) {
// this is not a valid JID
$input.addClass('error');
return;
}
converse.getVCard(
jid,
$.proxy(function (jid, fullname, image, image_type, url) {
// XXX: Should we perhaps create a roster item here?
this.addContact(jid, fullname);
}, this),
$.proxy(function () {
console.log("An error occured while fetching vcard");
}, this));
$('.search-xmpp').hide();
},
subscribeToContact: function (ev) { addContactFromList: function (ev) {
ev.preventDefault(); ev.preventDefault();
var $target = $(ev.target), var $target = $(ev.target),
jid = $target.attr('data-recipient'), jid = $target.attr('data-recipient'),
name = $target.text(); name = $target.text();
xmppchat.connection.roster.add(jid, name, [], function (iq) { this.addContact(jid, name);
xmppchat.connection.roster.subscribe(jid, null, xmppchat.fullname);
});
$target.parent().remove(); $target.parent().remove();
$('.search-xmpp').hide(); $('.search-xmpp').hide();
},
addContact: function (jid, name) {
converse.connection.roster.add(jid, name, [], function (iq) {
converse.connection.roster.subscribe(jid, null, converse.fullname);
});
} }
}); });
xmppchat.RoomsPanel = Backbone.View.extend({ converse.RoomsPanel = Backbone.View.extend({
tagName: 'div', tagName: 'div',
id: 'chatrooms', id: 'chatrooms',
events: { events: {
...@@ -688,7 +732,7 @@ ...@@ -688,7 +732,7 @@
}, },
updateRoomsList: function () { updateRoomsList: function () {
xmppchat.connection.muc.listRooms(xmppchat.muc_domain, $.proxy(function (iq) { converse.connection.muc.listRooms(converse.muc_domain, $.proxy(function (iq) {
var name, jid, i, var name, jid, i,
rooms = $(iq).find('query').find('item'), rooms = $(iq).find('query').find('item'),
rooms_length = rooms.length, rooms_length = rooms.length,
...@@ -718,23 +762,23 @@ ...@@ -718,23 +762,23 @@
name = input.val().trim().toLowerCase(); name = input.val().trim().toLowerCase();
input.val(''); // Clear the input input.val(''); // Clear the input
if (name) { if (name) {
jid = Strophe.escapeNode(name) + '@' + xmppchat.muc_domain; jid = Strophe.escapeNode(name) + '@' + converse.muc_domain;
} else { } else {
return; return;
} }
} }
xmppchat.chatboxes.create({ converse.chatboxes.create({
'id': jid, 'id': jid,
'jid': jid, 'jid': jid,
'name': Strophe.unescapeNode(Strophe.getNodeFromJid(jid)), 'name': Strophe.unescapeNode(Strophe.getNodeFromJid(jid)),
'nick': xmppchat.xmppstatus.get('fullname')||xmppchat.bare_jid, 'nick': converse.xmppstatus.get('fullname')||converse.bare_jid,
'chatroom': true, 'chatroom': true,
'box_id' : hex_sha1(jid) 'box_id' : hex_sha1(jid)
}); });
} }
}); });
xmppchat.ControlBoxView = xmppchat.ChatBoxView.extend({ converse.ControlBoxView = converse.ChatBoxView.extend({
tagName: 'div', tagName: 'div',
className: 'chatbox', className: 'chatbox',
id: 'controlbox', id: 'controlbox',
...@@ -744,7 +788,7 @@ ...@@ -744,7 +788,7 @@
}, },
initialize: function () { initialize: function () {
this.$el.appendTo(xmppchat.chatboxesview.$el); this.$el.appendTo(converse.chatboxesview.$el);
this.model.on('change', $.proxy(function (item, changed) { this.model.on('change', $.proxy(function (item, changed) {
if (_.has(item.changed, 'connected')) { if (_.has(item.changed, 'connected')) {
this.render(); this.render();
...@@ -752,7 +796,7 @@ ...@@ -752,7 +796,7 @@
if (_.has(item.changed, 'visible')) { if (_.has(item.changed, 'visible')) {
if (item.changed.visible === true) { if (item.changed.visible === true) {
this.show(); this.show();
} }
} }
}, this)); }, this));
...@@ -761,7 +805,7 @@ ...@@ -761,7 +805,7 @@
this.model.on('hide', this.hide, this); this.model.on('hide', this.hide, this);
if (this.model.get('visible')) { if (this.model.get('visible')) {
this.show(); this.show();
} }
}, },
template: _.template( template: _.template(
...@@ -794,17 +838,17 @@ ...@@ -794,17 +838,17 @@
render: function () { render: function () {
this.$el.html(this.template(this.model.toJSON())); this.$el.html(this.template(this.model.toJSON()));
if ((!xmppchat.prebind) && (!xmppchat.connection)) { if ((!converse.prebind) && (!converse.connection)) {
// Add login panel if the user still has to authenticate // Add login panel if the user still has to authenticate
this.loginpanel = new xmppchat.LoginPanel(); this.loginpanel = new converse.LoginPanel();
this.loginpanel.$parent = this.$el; this.loginpanel.$parent = this.$el;
this.loginpanel.render(); this.loginpanel.render();
} else { } else {
this.contactspanel = new xmppchat.ContactsPanel(); this.contactspanel = new converse.ContactsPanel();
this.contactspanel.$parent = this.$el; this.contactspanel.$parent = this.$el;
this.contactspanel.render(); this.contactspanel.render();
// TODO: Only add the rooms panel if the server supports MUC // TODO: Only add the rooms panel if the server supports MUC
this.roomspanel = new xmppchat.RoomsPanel(); this.roomspanel = new converse.RoomsPanel();
this.roomspanel.$parent = this.$el; this.roomspanel.$parent = this.$el;
this.roomspanel.render(); this.roomspanel.render();
} }
...@@ -812,7 +856,7 @@ ...@@ -812,7 +856,7 @@
} }
}); });
xmppchat.ChatRoomView = xmppchat.ChatBoxView.extend({ converse.ChatRoomView = converse.ChatBoxView.extend({
length: 300, length: 300,
tagName: 'div', tagName: 'div',
className: 'chatroom', className: 'chatroom',
...@@ -829,19 +873,19 @@ ...@@ -829,19 +873,19 @@
// TODO: Private messages // TODO: Private messages
break; break;
case 'topic': case 'topic':
xmppchat.connection.muc.setTopic(this.model.get('jid'), match[2]); converse.connection.muc.setTopic(this.model.get('jid'), match[2]);
break; break;
case 'kick': case 'kick':
xmppchat.connection.muc.kick(this.model.get('jid'), match[2]); converse.connection.muc.kick(this.model.get('jid'), match[2]);
break; break;
case 'ban': case 'ban':
xmppchat.connection.muc.ban(this.model.get('jid'), match[2]); converse.connection.muc.ban(this.model.get('jid'), match[2]);
break; break;
case 'op': case 'op':
xmppchat.connection.muc.op(this.model.get('jid'), match[2]); converse.connection.muc.op(this.model.get('jid'), match[2]);
break; break;
case 'deop': case 'deop':
xmppchat.connection.muc.deop(this.model.get('jid'), match[2]); converse.connection.muc.deop(this.model.get('jid'), match[2]);
break; break;
case 'help': case 'help':
$chat_content = this.$el.find('.chat-content'); $chat_content = this.$el.find('.chat-content');
...@@ -856,7 +900,7 @@ ...@@ -856,7 +900,7 @@
this.scrollDown(); this.scrollDown();
break; break;
default: default:
this.last_msgid = xmppchat.connection.muc.groupchat(this.model.get('jid'), body); this.last_msgid = converse.connection.muc.groupchat(this.model.get('jid'), body);
break; break;
} }
}, },
...@@ -883,7 +927,7 @@ ...@@ -883,7 +927,7 @@
'</div>'), '</div>'),
initialize: function () { initialize: function () {
xmppchat.connection.muc.join( converse.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),
...@@ -892,22 +936,22 @@ ...@@ -892,22 +936,22 @@
this.model.messages.on('add', this.showMessage, this); this.model.messages.on('add', this.showMessage, this);
this.model.on('destroy', function (model, response, options) { this.model.on('destroy', function (model, response, options) {
this.$el.hide('fast'); this.$el.hide('fast');
xmppchat.connection.muc.leave( converse.connection.muc.leave(
this.model.get('jid'), this.model.get('jid'),
this.model.get('nick'), this.model.get('nick'),
this.onLeave, this.onLeave,
undefined); undefined);
}, },
this); this);
this.$el.appendTo(xmppchat.chatboxesview.$el); this.$el.appendTo(converse.chatboxesview.$el);
this.render().show().model.messages.fetch({add: true}); this.render().show().model.messages.fetch({add: true});
xmppchat.clearMsgCounter(); converse.clearMsgCounter();
}, },
onLeave: function () { onLeave: function () {
var controlboxview = xmppchat.chatboxesview.views.controlbox; var controlboxview = converse.chatboxesview.views.controlbox;
if (controlboxview) { if (controlboxview) {
controlboxview.roomspanel.trigger('update-rooms-list'); controlboxview.roomspanel.trigger('update-rooms-list');
} }
...@@ -944,7 +988,7 @@ ...@@ -944,7 +988,7 @@
} }
if (delayed) { if (delayed) {
stamp = $message.find('delay').attr('stamp'); stamp = $message.find('delay').attr('stamp');
message_datetime = xmppchat.parseISO8601(stamp); message_datetime = converse.parseISO8601(stamp);
} else { } else {
message_datetime = new Date(); message_datetime = new Date();
} }
...@@ -953,7 +997,7 @@ ...@@ -953,7 +997,7 @@
dates = $chat_content.find("time").map(function(){return $(this).attr("datetime");}).get(); dates = $chat_content.find("time").map(function(){return $(this).attr("datetime");}).get();
message_date = message_datetime; message_date = message_datetime;
message_date.setUTCHours(0,0,0,0); message_date.setUTCHours(0,0,0,0);
isodate = xmppchat.toISOString(message_date); isodate = converse.toISOString(message_date);
if (_.indexOf(dates, isodate) == -1) { if (_.indexOf(dates, isodate) == -1) {
$chat_content.append(this.new_day_template({ $chat_content.append(this.new_day_template({
isodate: isodate, isodate: isodate,
...@@ -986,7 +1030,7 @@ ...@@ -986,7 +1030,7 @@
onChatRoomRoster: function (roster, room) { onChatRoomRoster: function (roster, room) {
// underscore size is needed because roster is an object // underscore size is needed because roster is an object
var controlboxview = xmppchat.chatboxesview.views.controlbox, var controlboxview = converse.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'),
participants = [], participants = [],
...@@ -1010,12 +1054,12 @@ ...@@ -1010,12 +1054,12 @@
} }
}); });
xmppchat.ChatBoxes = Backbone.Collection.extend({ converse.ChatBoxes = Backbone.Collection.extend({
model: xmppchat.ChatBox, model: converse.ChatBox,
onConnected: function () { onConnected: function () {
this.localStorage = new Backbone.LocalStorage( this.localStorage = new Backbone.LocalStorage(
hex_sha1('converse.chatboxes-'+xmppchat.bare_jid)); hex_sha1('converse.chatboxes-'+converse.bare_jid));
if (!this.get('controlbox')) { if (!this.get('controlbox')) {
this.add({ this.add({
id: 'controlbox', id: 'controlbox',
...@@ -1035,14 +1079,14 @@ ...@@ -1035,14 +1079,14 @@
this.get('controlbox').set({visible:true}).save(); this.get('controlbox').set({visible:true}).save();
} }
}, this) }, this)
}); });
}, },
messageReceived: function (message) { messageReceived: function (message) {
var partner_jid, $message = $(message), var partner_jid, $message = $(message),
message_from = $message.attr('from'); message_from = $message.attr('from');
if (message_from == xmppchat.connection.jid) { if (message_from == converse.connection.jid) {
// FIXME: Forwarded messages should be sent to specific resources, // FIXME: Forwarded messages should be sent to specific resources,
// not broadcasted // not broadcasted
return true; return true;
} }
...@@ -1053,7 +1097,7 @@ ...@@ -1053,7 +1097,7 @@
var from = Strophe.getBareJidFromJid(message_from), var from = Strophe.getBareJidFromJid(message_from),
to = Strophe.getBareJidFromJid($message.attr('to')), to = Strophe.getBareJidFromJid($message.attr('to')),
resource, chatbox; resource, chatbox;
if (from == xmppchat.bare_jid) { if (from == converse.bare_jid) {
// I am the sender, so this must be a forwarded message... // I am the sender, so this must be a forwarded message...
partner_jid = to; partner_jid = to;
resource = Strophe.getResourceFromJid($message.attr('to')); resource = Strophe.getResourceFromJid($message.attr('to'));
...@@ -1063,8 +1107,8 @@ ...@@ -1063,8 +1107,8 @@
} }
chatbox = this.get(partner_jid); chatbox = this.get(partner_jid);
if (!chatbox) { if (!chatbox) {
xmppchat.getVCard( converse.getVCard(
partner_jid, partner_jid,
$.proxy(function (jid, fullname, image, image_type, url) { $.proxy(function (jid, fullname, image, image_type, url) {
var chatbox = this.create({ var chatbox = this.create({
'id': jid, 'id': jid,
...@@ -1075,7 +1119,7 @@ ...@@ -1075,7 +1119,7 @@
'url': url 'url': url
}); });
chatbox.messageReceived(message); chatbox.messageReceived(message);
xmppchat.roster.addResource(partner_jid, resource); converse.roster.addResource(partner_jid, resource);
}, this), }, this),
$.proxy(function () { $.proxy(function () {
// # FIXME // # FIXME
...@@ -1084,12 +1128,12 @@ ...@@ -1084,12 +1128,12 @@
return true; return true;
} }
chatbox.messageReceived(message); chatbox.messageReceived(message);
xmppchat.roster.addResource(partner_jid, resource); converse.roster.addResource(partner_jid, resource);
return true; return true;
} }
}); });
xmppchat.ChatBoxesView = Backbone.View.extend({ converse.ChatBoxesView = Backbone.View.extend({
el: '#collective-xmpp-chat-data', el: '#collective-xmpp-chat-data',
initialize: function () { initialize: function () {
...@@ -1099,12 +1143,12 @@ ...@@ -1099,12 +1143,12 @@
var view = this.views[item.get('id')]; var view = this.views[item.get('id')];
if (!view) { if (!view) {
if (item.get('chatroom')) { if (item.get('chatroom')) {
view = new xmppchat.ChatRoomView({'model': item}); view = new converse.ChatRoomView({'model': item});
} else if (item.get('box_id') === 'controlbox') { } else if (item.get('box_id') === 'controlbox') {
view = new xmppchat.ControlBoxView({model: item}); view = new converse.ControlBoxView({model: item});
view.render(); view.render();
} else { } else {
view = new xmppchat.ChatBoxView({model: item}); view = new converse.ChatBoxView({model: item});
} }
this.views[item.get('id')] = view; this.views[item.get('id')] = view;
} else { } else {
...@@ -1119,7 +1163,7 @@ ...@@ -1119,7 +1163,7 @@
} }
}); });
xmppchat.RosterItem = Backbone.Model.extend({ converse.RosterItem = Backbone.Model.extend({
initialize: function (attributes, options) { initialize: function (attributes, options) {
var jid = attributes.jid; var jid = attributes.jid;
if (!attributes.fullname) { if (!attributes.fullname) {
...@@ -1137,7 +1181,7 @@ ...@@ -1137,7 +1181,7 @@
} }
}); });
xmppchat.RosterItemView = Backbone.View.extend({ converse.RosterItemView = Backbone.View.extend({
tagName: 'dd', tagName: 'dd',
events: { events: {
...@@ -1150,11 +1194,11 @@ ...@@ -1150,11 +1194,11 @@
openChat: function (ev) { openChat: function (ev) {
ev.preventDefault(); ev.preventDefault();
var jid = Strophe.getBareJidFromJid(this.model.get('jid')), var jid = Strophe.getBareJidFromJid(this.model.get('jid')),
chatbox = xmppchat.chatboxes.get(jid); chatbox = converse.chatboxes.get(jid);
if (chatbox) { if (chatbox) {
chatbox.trigger('show'); chatbox.trigger('show');
} else { } else {
xmppchat.chatboxes.create({ converse.chatboxes.create({
'id': this.model.get('jid'), 'id': this.model.get('jid'),
'jid': this.model.get('jid'), 'jid': this.model.get('jid'),
'fullname': this.model.get('fullname'), 'fullname': this.model.get('fullname'),
...@@ -1170,25 +1214,25 @@ ...@@ -1170,25 +1214,25 @@
var result = confirm("Are you sure you want to remove this contact?"); var result = confirm("Are you sure you want to remove this contact?");
if (result === true) { if (result === true) {
var bare_jid = this.model.get('jid'); var bare_jid = this.model.get('jid');
xmppchat.connection.roster.remove(bare_jid, function (iq) { converse.connection.roster.remove(bare_jid, function (iq) {
xmppchat.connection.roster.unauthorize(bare_jid); converse.connection.roster.unauthorize(bare_jid);
xmppchat.rosterview.model.remove(bare_jid); converse.rosterview.model.remove(bare_jid);
}); });
} }
}, },
acceptRequest: function (ev) { acceptRequest: function (ev) {
var jid = this.model.get('jid'); var jid = this.model.get('jid');
xmppchat.connection.roster.authorize(jid); converse.connection.roster.authorize(jid);
xmppchat.connection.roster.add(jid, this.model.get('fullname'), [], function (iq) { converse.connection.roster.add(jid, this.model.get('fullname'), [], function (iq) {
xmppchat.connection.roster.subscribe(jid, null, xmppchat.fullname); converse.connection.roster.subscribe(jid, null, converse.fullname);
}); });
ev.preventDefault(); ev.preventDefault();
}, },
declineRequest: function (ev) { declineRequest: function (ev) {
ev.preventDefault(); ev.preventDefault();
xmppchat.connection.roster.unauthorize(this.model.get('jid')); converse.connection.roster.unauthorize(this.model.get('jid'));
this.model.destroy(); this.model.destroy();
}, },
...@@ -1219,7 +1263,7 @@ ...@@ -1219,7 +1263,7 @@
} else if (ask === 'request') { } else if (ask === 'request') {
this.$el.addClass('requesting-xmpp-contact'); this.$el.addClass('requesting-xmpp-contact');
this.$el.html(this.request_template(item.toJSON())); this.$el.html(this.request_template(item.toJSON()));
xmppchat.showControlBox(); converse.showControlBox();
} else if (subscription === 'both' || subscription === 'to') { } else if (subscription === 'both' || subscription === 'to') {
this.$el.addClass('current-xmpp-contact'); this.$el.addClass('current-xmpp-contact');
this.$el.html(this.template(item.toJSON())); this.$el.html(this.template(item.toJSON()));
...@@ -1237,8 +1281,8 @@ ...@@ -1237,8 +1281,8 @@
} }
}); });
xmppchat.getVCard = function (jid, callback, errback) { converse.getVCard = function (jid, callback, errback) {
xmppchat.connection.vcard.get($.proxy(function (iq) { converse.connection.vcard.get($.proxy(function (iq) {
$vcard = $(iq).find('vCard'); $vcard = $(iq).find('vCard');
var fullname = $vcard.find('FN').text(), var fullname = $vcard.find('FN').text(),
img = $vcard.find('BINVAL').text(), img = $vcard.find('BINVAL').text(),
...@@ -1248,8 +1292,8 @@ ...@@ -1248,8 +1292,8 @@
}, this), jid, errback); }, this), jid, errback);
} }
xmppchat.RosterItems = Backbone.Collection.extend({ converse.RosterItems = Backbone.Collection.extend({
model: xmppchat.RosterItem, model: converse.RosterItem,
comparator : function (rosteritem) { comparator : function (rosteritem) {
var chat_status = rosteritem.get('chat_status'), var chat_status = rosteritem.get('chat_status'),
rank = 4; rank = 4;
...@@ -1283,8 +1327,8 @@ ...@@ -1283,8 +1327,8 @@
action = $this.attr('action'), action = $this.attr('action'),
fullname = $this.attr('name'); fullname = $this.attr('name');
if (action === 'add') { if (action === 'add') {
xmppchat.connection.roster.add(jid, fullname, [], function (iq) { converse.connection.roster.add(jid, fullname, [], function (iq) {
xmppchat.connection.roster.subscribe(jid, null, xmppchat.fullname); converse.connection.roster.subscribe(jid, null, converse.fullname);
}); });
} }
}); });
...@@ -1292,7 +1336,7 @@ ...@@ -1292,7 +1336,7 @@
}, },
isSelf: function (jid) { isSelf: function (jid) {
return (Strophe.getBareJidFromJid(jid) === Strophe.getBareJidFromJid(xmppchat.connection.jid)); return (Strophe.getBareJidFromJid(jid) === Strophe.getBareJidFromJid(converse.connection.jid));
}, },
getItem: function (id) { getItem: function (id) {
...@@ -1333,13 +1377,13 @@ ...@@ -1333,13 +1377,13 @@
subscribeBack: function (jid) { subscribeBack: function (jid) {
var bare_jid = Strophe.getBareJidFromJid(jid); var bare_jid = Strophe.getBareJidFromJid(jid);
if (xmppchat.connection.roster.findItem(bare_jid)) { if (converse.connection.roster.findItem(bare_jid)) {
xmppchat.connection.roster.authorize(bare_jid); converse.connection.roster.authorize(bare_jid);
xmppchat.connection.roster.subscribe(jid, null, xmppchat.fullname); converse.connection.roster.subscribe(jid, null, converse.fullname);
} else { } else {
xmppchat.connection.roster.add(jid, '', [], function (iq) { converse.connection.roster.add(jid, '', [], function (iq) {
xmppchat.connection.roster.authorize(bare_jid); converse.connection.roster.authorize(bare_jid);
xmppchat.connection.roster.subscribe(jid, null, xmppchat.fullname); converse.connection.roster.subscribe(jid, null, converse.fullname);
}); });
} }
}, },
...@@ -1351,10 +1395,10 @@ ...@@ -1351,10 +1395,10 @@
* this step lets the user's server know that it MUST no longer * this step lets the user's server know that it MUST no longer
* send notification of the subscription state change to the user. * send notification of the subscription state change to the user.
*/ */
xmppchat.xmppstatus.sendPresence('unsubscribe'); converse.xmppstatus.sendPresence('unsubscribe');
if (xmppchat.connection.roster.findItem(jid)) { if (converse.connection.roster.findItem(jid)) {
xmppchat.connection.roster.remove(jid, function (iq) { converse.connection.roster.remove(jid, function (iq) {
xmppchat.rosterview.model.remove(jid); converse.rosterview.model.remove(jid);
}); });
} }
}, },
...@@ -1399,10 +1443,10 @@ ...@@ -1399,10 +1443,10 @@
is_last = false; is_last = false;
if (index === (items.length-1)) { is_last = true; } if (index === (items.length-1)) { is_last = true; }
this.create({ this.create({
jid: item.jid, jid: item.jid,
subscription: item.subscription, subscription: item.subscription,
ask: item.ask, ask: item.ask,
fullname: item.name, fullname: item.name || item.jid,
is_last: is_last is_last: is_last
}); });
} else { } else {
...@@ -1431,11 +1475,11 @@ ...@@ -1431,11 +1475,11 @@
item; item;
if (this.isSelf(bare_jid)) { if (this.isSelf(bare_jid)) {
if ((xmppchat.connection.jid !== jid)&&(presence_type !== 'unavailabe')) { if ((converse.connection.jid !== jid)&&(presence_type !== 'unavailabe')) {
// Another resource has changed it's status, we'll update ours as well. // Another resource has changed it's status, we'll update ours as well.
// FIXME: We should ideally differentiate between converse.js using // FIXME: We should ideally differentiate between converse.js using
// resources and other resources (i.e Pidgin etc.) // resources and other resources (i.e Pidgin etc.)
xmppchat.xmppstatus.set({'status': chat_status}); converse.xmppstatus.set({'status': chat_status});
} }
return true; return true;
} else if (($presence.find('x').attr('xmlns') || '').indexOf(Strophe.NS.MUC) === 0) { } else if (($presence.find('x').attr('xmlns') || '').indexOf(Strophe.NS.MUC) === 0) {
...@@ -1450,21 +1494,21 @@ ...@@ -1450,21 +1494,21 @@
if ((presence_type === 'error') || (presence_type === 'subscribed') || (presence_type === 'unsubscribe')) { if ((presence_type === 'error') || (presence_type === 'subscribed') || (presence_type === 'unsubscribe')) {
return true; return true;
} else if (presence_type === 'subscribe') { } else if (presence_type === 'subscribe') {
if (xmppchat.auto_subscribe) { if (converse.auto_subscribe) {
if ((!item) || (item.get('subscription') != 'to')) { if ((!item) || (item.get('subscription') != 'to')) {
this.subscribeBack(jid); this.subscribeBack(jid);
} else { } else {
xmppchat.connection.roster.authorize(bare_jid); converse.connection.roster.authorize(bare_jid);
} }
} else { } else {
if ((item) && (item.get('subscription') != 'none')) { if ((item) && (item.get('subscription') != 'none')) {
xmppchat.connection.roster.authorize(bare_jid); converse.connection.roster.authorize(bare_jid);
} else { } else {
xmppchat.getVCard( converse.getVCard(
bare_jid, bare_jid,
$.proxy(function (jid, fullname, img, img_type, url) { $.proxy(function (jid, fullname, img, img_type, url) {
this.add({ this.add({
jid: bare_jid, jid: bare_jid,
subscription: 'none', subscription: 'none',
ask: 'request', ask: 'request',
fullname: fullname, fullname: fullname,
...@@ -1498,9 +1542,9 @@ ...@@ -1498,9 +1542,9 @@
} }
}); });
xmppchat.RosterView = Backbone.View.extend({ converse.RosterView = Backbone.View.extend({
tagName: 'dl', tagName: 'dl',
id: 'xmppchat-roster', id: 'converse-roster',
rosteritemviews: {}, rosteritemviews: {},
removeRosterItem: function (item) { removeRosterItem: function (item) {
...@@ -1514,7 +1558,7 @@ ...@@ -1514,7 +1558,7 @@
initialize: function () { initialize: function () {
this.model.on("add", function (item) { this.model.on("add", function (item) {
var view = new xmppchat.RosterItemView({model: item}); var view = new converse.RosterItemView({model: item});
this.rosteritemviews[item.id] = view; this.rosteritemviews[item.id] = view;
this.render(item); this.render(item);
}, this); }, this);
...@@ -1534,11 +1578,11 @@ ...@@ -1534,11 +1578,11 @@
this.$el.hide().html(this.template()); this.$el.hide().html(this.template());
this.model.fetch({add: true}); // Get the cached roster items from localstorage this.model.fetch({add: true}); // Get the cached roster items from localstorage
this.initialSort(); this.initialSort();
this.$el.appendTo(xmppchat.chatboxesview.views.controlbox.contactspanel.$el); this.$el.appendTo(converse.chatboxesview.views.controlbox.contactspanel.$el);
}, },
updateChatBox: function (item, changed) { updateChatBox: function (item, changed) {
var chatbox = xmppchat.chatboxes.get(item.get('jid')), var chatbox = converse.chatboxes.get(item.get('jid')),
changes = {}; changes = {};
if (!chatbox) { return; } if (!chatbox) { return; }
if (_.has(item.changed, 'chat_status')) { if (_.has(item.changed, 'chat_status')) {
...@@ -1626,11 +1670,10 @@ ...@@ -1626,11 +1670,10 @@
crit = {order:'asc'}; crit = {order:'asc'};
$my_contacts.after($my_contacts.siblings('dd.current-xmpp-contact.offline').tsort('a', crit)); $my_contacts.after($my_contacts.siblings('dd.current-xmpp-contact.offline').tsort('a', crit));
$my_contacts.after($my_contacts.siblings('dd.current-xmpp-contact.unavailable').tsort('a', crit)); $my_contacts.after($my_contacts.siblings('dd.current-xmpp-contact.unavailable').tsort('a', crit));
}, }
}); });
xmppchat.XMPPStatus = Backbone.Model.extend({ converse.XMPPStatus = Backbone.Model.extend({
initialize: function () { initialize: function () {
this.set({ this.set({
'status' : this.get('status'), 'status' : this.get('status'),
...@@ -1648,7 +1691,7 @@ ...@@ -1648,7 +1691,7 @@
}, },
sendPresence: function (type) { sendPresence: function (type) {
var status_message = this.get('status_message'), var status_message = this.get('status_message'),
presence; presence;
// Most of these presence types are actually not explicitly sent, // Most of these presence types are actually not explicitly sent,
// but I add all of them here fore reference and future proofing. // but I add all of them here fore reference and future proofing.
...@@ -1670,7 +1713,7 @@ ...@@ -1670,7 +1713,7 @@
presence.c('status').t(status_message); presence.c('status').t(status_message);
} }
} }
xmppchat.connection.send(presence); converse.connection.send(presence);
}, },
setStatus: function (value) { setStatus: function (value) {
...@@ -1679,13 +1722,13 @@ ...@@ -1679,13 +1722,13 @@
}, },
setStatusMessage: function (status_message) { setStatusMessage: function (status_message) {
xmppchat.connection.send($pres().c('show').t(this.get('status')).up().c('status').t(status_message)); converse.connection.send($pres().c('show').t(this.get('status')).up().c('status').t(status_message));
this.save({'status_message': status_message}); this.save({'status_message': status_message});
} }
}); });
xmppchat.XMPPStatusView = Backbone.View.extend({ converse.XMPPStatusView = Backbone.View.extend({
el: "span#xmpp-status-holder", el: "span#xmpp-status-holder",
events: { events: {
...@@ -1756,7 +1799,7 @@ ...@@ -1756,7 +1799,7 @@
if (!(_.has(model.changed, 'status')) && !(_.has(model.changed, 'status_message'))) { if (!(_.has(model.changed, 'status')) && !(_.has(model.changed, 'status_message'))) {
return; return;
} }
var stat = model.get('status'), var stat = model.get('status'),
status_message = model.get('status_message') || "I am " + this.getPrettyStatus(stat); status_message = model.get('status_message') || "I am " + this.getPrettyStatus(stat);
this.$el.find('#fancy-xmpp-status-select').html( this.$el.find('#fancy-xmpp-status-select').html(
this.status_template({ this.status_template({
...@@ -1811,16 +1854,16 @@ ...@@ -1811,16 +1854,16 @@
} }
}); });
xmppchat.LoginPanel = Backbone.View.extend({ converse.LoginPanel = Backbone.View.extend({
tagName: 'div', tagName: 'div',
id: "login-dialog", id: "login-dialog",
events: { events: {
'submit form#xmppchat-login': 'authenticate' 'submit form#converse-login': 'authenticate'
}, },
tab_template: _.template( tab_template: _.template(
'<li><a class="current" href="#login">Sign in</a></li>'), '<li><a class="current" href="#login">Sign in</a></li>'),
template: _.template( template: _.template(
'<form id="xmppchat-login">' + '<form id="converse-login">' +
'<label>XMPP ID:</label>' + '<label>XMPP ID:</label>' +
'<input type="text" id="jid">' + '<input type="text" id="jid">' +
'<label>Password:</label>' + '<label>Password:</label>' +
...@@ -1833,30 +1876,53 @@ ...@@ -1833,30 +1876,53 @@
authenticate: function (ev) { authenticate: function (ev) {
ev.preventDefault(); ev.preventDefault();
var $form = $(ev.target), var $form = $(ev.target),
bosh_service_url = $form.find('input#bosh_service_url').val(), $bsu_input = $form.find('input#bosh_service_url'),
jid = $form.find('input#jid').val(), bosh_service_url = $bsu_input.val(),
password = $form.find('input#password').val(), $jid_input = $form.find('input#jid'),
jid = $jid_input.val(),
$pw_input = $form.find('input#password'),
password = $pw_input.val(),
connection = new Strophe.Connection(bosh_service_url); connection = new Strophe.Connection(bosh_service_url);
var errors = false;
if (! jid) {
errors = true;
$jid_input.addClass('error');
}
if (! password) {
errors = true;
$pw_input.addClass('error');
}
if (! bosh_service_url) {
errors = true;
$bsu_input.addClass('error');
}
if (errors) { return; }
// Clear the form's fields, so that it can't be submitted twice
$bsu_input.val('');
$jid_input.val('');
$pw_input.val('');
connection.connect(jid, password, $.proxy(function (status) { connection.connect(jid, password, $.proxy(function (status) {
if (status === Strophe.Status.CONNECTED) { if (status === Strophe.Status.CONNECTED) {
$(document).trigger('jarnxmpp.connected', connection); console.log('Connected');
converse.onConnected(connection);
} else if (status === Strophe.Status.DISCONNECTED) { } else if (status === Strophe.Status.DISCONNECTED) {
console.log('Disconnected'); console.log('Disconnected');
$(document).trigger('jarnxmpp.disconnected'); this.$feedback.text('Unable to communicate with chat server').css('background-image', "url(images/error_icon.png)");
} else if (status === Strophe.Status.Error) { } else if (status === Strophe.Status.Error) {
console.log('Error'); console.log('Error');
} else if (status === Strophe.Status.CONNECTING) { } else if (status === Strophe.Status.CONNECTING) {
console.log('Connecting'); console.log('Connecting');
$(document).trigger('jarnxmpp.connecting'); this.$feedback.text('Connecting to chat...');
} else if (status === Strophe.Status.CONNFAIL) { } else if (status === Strophe.Status.CONNFAIL) {
console.log('Connection Failed'); console.log('Connection Failed');
} else if (status === Strophe.Status.AUTHENTICATING) { } else if (status === Strophe.Status.AUTHENTICATING) {
console.log('Authenticating'); console.log('Authenticating');
xmppchat.giveFeedback('Authenticating'); converse.giveFeedback('Authenticating');
} else if (status === Strophe.Status.AUTHFAIL) { } else if (status === Strophe.Status.AUTHFAIL) {
console.log('Authenticating Failed'); console.log('Authenticating Failed');
xmppchat.giveFeedback('Authentication failed'); converse.giveFeedback('Authentication failed');
} else if (status === Strophe.Status.DISCONNECTING) { } else if (status === Strophe.Status.DISCONNECTING) {
console.log('Disconnecting'); console.log('Disconnecting');
} else if (status === Strophe.Status.ATTACHED) { } else if (status === Strophe.Status.ATTACHED) {
...@@ -1877,7 +1943,7 @@ ...@@ -1877,7 +1943,7 @@
} }
}); });
xmppchat.showControlBox = function () { converse.showControlBox = function () {
var controlbox = this.chatboxes.get('controlbox'); var controlbox = this.chatboxes.get('controlbox');
if (!controlbox) { if (!controlbox) {
this.chatboxes.add({ this.chatboxes.add({
...@@ -1893,7 +1959,7 @@ ...@@ -1893,7 +1959,7 @@
} }
} }
xmppchat.toggleControlBox = function () { converse.toggleControlBox = function () {
if ($("div#controlbox").is(':visible')) { if ($("div#controlbox").is(':visible')) {
var controlbox = this.chatboxes.get('controlbox'); var controlbox = this.chatboxes.get('controlbox');
if (this.connection) { if (this.connection) {
...@@ -1906,28 +1972,14 @@ ...@@ -1906,28 +1972,14 @@
} }
}; };
xmppchat.giveFeedback = function (message) { converse.giveFeedback = function (message) {
$('.conn-feedback').text(message); $('.conn-feedback').text(message);
} }
xmppchat.initialize = function () { converse.onConnected = function (connection) {
var chatdata = $('div#collective-xmpp-chat-data'); this.connection = connection;
this.fullname = chatdata.attr('fullname');
this.prebind = chatdata.attr('prebind');
this.auto_subscribe = chatdata.attr('auto_subscribe') === "True" || false;
this.chatboxes = new this.ChatBoxes();
this.chatboxesview = new this.ChatBoxesView({model: this.chatboxes});
$('a.toggle-online-users').bind(
'click',
$.proxy(function (e) {
e.preventDefault(); this.toggleControlBox();
}, this)
);
},
xmppchat.onConnected = function (connection) {
this.animate = true; // Use animations this.animate = true; // Use animations
this.connection = connection;
this.connection.xmlInput = function (body) { console.log(body); }; this.connection.xmlInput = function (body) { console.log(body); };
this.connection.xmlOutput = function (body) { console.log(body); }; this.connection.xmlOutput = function (body) { console.log(body); };
this.bare_jid = Strophe.getBareJidFromJid(this.connection.jid); this.bare_jid = Strophe.getBareJidFromJid(this.connection.jid);
...@@ -1975,22 +2027,22 @@ ...@@ -1975,22 +2027,22 @@
this.giveFeedback('Online Contacts'); this.giveFeedback('Online Contacts');
}; };
// Event handlers converse.initialize = function (settings) {
// -------------- this.prebind = settings.prebind;
$(document).ready($.proxy(function () { this.fullname = settings.fullname;
this.initialize(); this.xhr_user_search = settings.xhr_user_search;
$(document).bind('jarnxmpp.connecting', $.proxy(function (ev, conn) { this.auto_subscribe = settings.auto_subscribe;
this.giveFeedback('Connecting to chat...'); this.animate = settings.animate;
}, this));
$(document).bind('jarnxmpp.disconnected', $.proxy(function (ev, conn) { this.chatboxes = new this.ChatBoxes();
this.giveFeedback('Unable to communicate with chat server').css('background-image', "url(images/error_icon.png)"); this.chatboxesview = new this.ChatBoxesView({model: this.chatboxes});
console.log("Connection Failed :("); $('a.toggle-online-users').bind(
}, this)); 'click',
$(document).unbind('jarnxmpp.connected'); $.proxy(function (e) {
$(document).bind('jarnxmpp.connected', $.proxy(function (ev, connection) { e.preventDefault(); this.toggleControlBox();
this.onConnected(connection); }, this)
}, this)); );
}, xmppchat)); };
return xmppchat; return converse;
})); }));
=========================
Converse.js Documentation
=========================
------------------------------------
Converse.js configuration variables:
------------------------------------
Prebind
========
Use this option if you don't want to render the login form on the chat control
box.
When set to true, the onConnected method needs to be called manually, together
with a Strophe connection object.
The most likely usecase is if you want to already authenticate on the backend
and merely attach to that connection in the browser.
Besides requiring the back-end to authenticate you, you'll also
have to write a Javascript snippet to attach to the set up connection::
$.JSON({
'url': 'mysite.com/xmpp-authenticate',
'success': function (data) {
connection = new Strophe.Connection(data.BOSH_SERVICE_URL);
connection.attach(data.jid, data.sid, data.rid, converse.onConnected);
}
fullname
========
If you are using prebinding, you need to specify the fullname of the currently
logged in user.
xhr_user_search
===============
There are two ways to add users.
* The user inputs a valid JID (Jabber ID), and the user is added as a pending
contact.
* The user inputs some text (for example part of a firstname or lastname), an XHR will be made to a backend, and a list of matches are returned. The user can then choose one of the matches to add as a contact.
This setting enables the second mechanism, otherwise by default the first will
be used.
auto_subscribe
==============
If true, the user will automatically subscribe back to any contact requests.
animate
=======
Show animations, for example when opening and closing chat boxes.
...@@ -29,16 +29,16 @@ ...@@ -29,16 +29,16 @@
<!-- MAIN CONTENT --> <!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer"> <div id="main_content_wrap" class="outer">
<section id="main_content" class="inner"> <section id="main_content" class="inner">
<p><strong>Converse.js</strong> implements an <a href="http://xmpp.org" target="_blank">XMPP</a> based instant messaging client in the browser.</p> <p><strong>Converse.js</strong> is a web based <a href="http://xmpp.org" target="_blank">XMPP/Jabber</a> instant messaging client.</p>
<p>It is used by <a href="http://github.com/collective/collective.xmpp.chat" target="_blank">collective.xmpp.chat</a>, which is a <a href="http://plone.org" target="_blank">Plone</a> instant messaging add-on.</p> <p>It is used by <a href="http://github.com/collective/collective.xmpp.chat" target="_blank">collective.xmpp.chat</a>, which is a <a href="http://plone.org" target="_blank">Plone</a> instant messaging add-on.</p>
<p>The ultimate goal is to enable anyone to add chat functionality to their websites, regardless of the backend.</p> <p>The ultimate goal is to enable anyone to add chat functionality to their websites, independent of any backend.
<p>This is currently possible, except for adding new contacts, which still makes an XHR call to the (Plone) backend to fetch user info.</p> You will however need an XMPP server to connect to, either your own, or a public one.</p>
<h2>Features</h2> <h2>Features</h2>
<ul> <ul>
<li>Manually or automically subscribe to other users.</li> <li>Manually or automically subscribe to other users.</li>
<li>Accept or decline contact requests</li> <li>Accept or decline contact requests</li>
<li>Chat status (online, busy, away, offline)</li> <li>Chat statuses (online, busy, away, offline)</li>
<li>Custom status messages</li> <li>Custom status messages</li>
<li>Typing notifications</li> <li>Typing notifications</li>
<li>Third person messages (/me )</li> <li>Third person messages (/me )</li>
...@@ -131,10 +131,10 @@ ...@@ -131,10 +131,10 @@
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E")); document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script> </script>
<script type="text/javascript">try { var pageTracker = _gat._getTracker("UA-2128260-8"); pageTracker._trackPageview(); } catch(err) {}</script> <script type="text/javascript">try { var pageTracker = _gat._getTracker("UA-2128260-8"); pageTracker._trackPageview(); } catch(err) {}</script>
</body> </body>
</html> </html>
require(["jquery", "converse"], function($) {}); require(["jquery", "converse"], function($, converse) {
converse.initialize({
prebind: false,
xhr_user_search: false,
auto_subscribe: false
});
});
(function (root, factory) { (function (root, factory) {
define([ define([
"converse" "converse"
], function (xmppchat) { ], function (converse) {
return factory(xmppchat); return factory(converse);
} }
); );
} (this, function (xmppchat) { } (this, function (converse) {
return describe("Converse.js", $.proxy(function() { return describe("Converse.js", $.proxy(function() {
// Names from http://www.fakenamegenerator.com/ // Names from http://www.fakenamegenerator.com/
...@@ -21,13 +21,12 @@ ...@@ -21,13 +21,12 @@
'Lena Grunewald', 'Laura Grunewald', 'Mandy Seiler', 'Sven Bosch', 'Nuriye Cuypers' 'Lena Grunewald', 'Laura Grunewald', 'Mandy Seiler', 'Sven Bosch', 'Nuriye Cuypers'
]; ];
var num_contacts = req_names.length + pend_names.length + cur_names.length; var num_contacts = req_names.length + pend_names.length + cur_names.length;
this.bare_jid = 'dummy@localhost';
mock_connection = { mock_connection = {
'muc': { 'muc': {
'listRooms': function () {}, 'listRooms': function () {},
'join': function () {} 'join': function () {}
}, },
'jid': this.bare_jid, 'jid': 'dummy@localhost',
'addHandler': function (handler, ns, name, type, id, from, options) { 'addHandler': function (handler, ns, name, type, id, from, options) {
return function () {}; return function () {};
}, },
...@@ -54,9 +53,13 @@ ...@@ -54,9 +53,13 @@
// Clear localStorage // Clear localStorage
window.localStorage.clear(); window.localStorage.clear();
this.prebind = true; this.initialize({
prebind: false,
xhr_user_search: false,
auto_subscribe: false,
animate: false
});
this.onConnected(mock_connection); this.onConnected(mock_connection);
this.animate = false; // don't use animations
// Variable declarations for specs // Variable declarations for specs
var open_controlbox; var open_controlbox;
...@@ -64,7 +67,7 @@ ...@@ -64,7 +67,7 @@
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)); }, converse));
open_controlbox = $.proxy(function () { open_controlbox = $.proxy(function () {
// This spec will only pass if the controlbox is not currently // This spec will only pass if the controlbox is not currently
...@@ -74,7 +77,7 @@ ...@@ -74,7 +77,7 @@
$('.toggle-online-users').click(); $('.toggle-online-users').click();
expect(this.toggleControlBox).toHaveBeenCalled(); expect(this.toggleControlBox).toHaveBeenCalled();
expect($("div#controlbox").is(':visible')).toBe(true); expect($("div#controlbox").is(':visible')).toBe(true);
}, xmppchat); }, converse);
it("can be opened by clicking a DOM element with class 'toggle-online-users'", open_controlbox); 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 () {
...@@ -100,8 +103,8 @@ ...@@ -100,8 +103,8 @@
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);
expect(view.$el.find('a.choose-xmpp-status span.value').text()).toBe('I am online'); expect(view.$el.find('a.choose-xmpp-status span.value').text()).toBe('I am online');
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
it("can be used to set a custom status message", $.proxy(function () { it("can be used to set a custom status message", $.proxy(function () {
var view = this.xmppstatusview; var view = this.xmppstatusview;
...@@ -123,17 +126,17 @@ ...@@ -123,17 +126,17 @@
expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true); expect(view.$el.find('a.choose-xmpp-status').hasClass('online')).toBe(true);
expect(view.$el.find('a.choose-xmpp-status span.value').text()).toBe(msg); expect(view.$el.find('a.choose-xmpp-status span.value').text()).toBe(msg);
}); });
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("The Contacts Roster", $.proxy(function () { describe("The Contacts Roster", $.proxy(function () {
describe("Pending Contacts", $.proxy(function () { describe("Pending Contacts", $.proxy(function () {
it("do not have a heading if there aren't any", $.proxy(function () { it("do not have a heading if there aren't any", $.proxy(function () {
expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('none'); expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('none');
}, xmppchat)); }, converse));
it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () { it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
var i, t, is_last; var i, t, is_last;
...@@ -159,17 +162,17 @@ ...@@ -159,17 +162,17 @@
t = this.rosterview.$el.find('dt#pending-xmpp-contacts').siblings('dd.pending-xmpp-contact').text(); t = this.rosterview.$el.find('dt#pending-xmpp-contacts').siblings('dd.pending-xmpp-contact').text();
expect(t).toEqual(pend_names.slice(0,i+1).sort().join('')); expect(t).toEqual(pend_names.slice(0,i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("will have their own heading once they have been added", $.proxy(function () { it("will have their own heading once they have been added", $.proxy(function () {
expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('block'); expect(this.rosterview.$el.find('dt#pending-xmpp-contacts').css('display')).toEqual('block');
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("Existing Contacts", $.proxy(function () { describe("Existing Contacts", $.proxy(function () {
it("do not have a heading if there aren't any", $.proxy(function () { it("do not have a heading if there aren't any", $.proxy(function () {
expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('none'); expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('none');
}, xmppchat)); }, converse));
it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () { it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
var i, t; var i, t;
...@@ -187,11 +190,11 @@ ...@@ -187,11 +190,11 @@
t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.offline').find('a.open-chat').text(); t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.offline').find('a.open-chat').text();
expect(t).toEqual(cur_names.slice(0,i+1).sort().join('')); expect(t).toEqual(cur_names.slice(0,i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("will have their own heading once they have been added", $.proxy(function () { it("will have their own heading once they have been added", $.proxy(function () {
expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('block'); expect(this.rosterview.$el.find('dt#xmpp-contacts').css('display')).toEqual('block');
}, xmppchat)); }, converse));
it("can change their status to online and be sorted alphabetically", $.proxy(function () { it("can change their status to online and be sorted alphabetically", $.proxy(function () {
var item, view, jid, t; var item, view, jid, t;
...@@ -209,7 +212,7 @@ ...@@ -209,7 +212,7 @@
t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.online').find('a.open-chat').text(); t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.online').find('a.open-chat').text();
expect(t).toEqual(cur_names.slice(0,i+1).sort().join('')); expect(t).toEqual(cur_names.slice(0,i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("can change their status to busy and be sorted alphabetically", $.proxy(function () { it("can change their status to busy and be sorted alphabetically", $.proxy(function () {
var item, view, jid, t; var item, view, jid, t;
...@@ -226,7 +229,7 @@ ...@@ -226,7 +229,7 @@
t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.dnd').find('a.open-chat').text(); t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.dnd').find('a.open-chat').text();
expect(t).toEqual(cur_names.slice(3,i+1).sort().join('')); expect(t).toEqual(cur_names.slice(3,i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("can change their status to away and be sorted alphabetically", $.proxy(function () { it("can change their status to away and be sorted alphabetically", $.proxy(function () {
var item, view, jid, t; var item, view, jid, t;
...@@ -244,7 +247,7 @@ ...@@ -244,7 +247,7 @@
t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.away').find('a.open-chat').text(); t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.away').find('a.open-chat').text();
expect(t).toEqual(cur_names.slice(6,i+1).sort().join('')); expect(t).toEqual(cur_names.slice(6,i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("can change their status to unavailable and be sorted alphabetically", $.proxy(function () { it("can change their status to unavailable and be sorted alphabetically", $.proxy(function () {
var item, view, jid, t; var item, view, jid, t;
...@@ -262,7 +265,7 @@ ...@@ -262,7 +265,7 @@
t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.unavailable').find('a.open-chat').text(); t = this.rosterview.$el.find('dt#xmpp-contacts').siblings('dd.current-xmpp-contact.unavailable').find('a.open-chat').text();
expect(t).toEqual(cur_names.slice(9, i+1).sort().join('')); expect(t).toEqual(cur_names.slice(9, i+1).sort().join(''));
} }
}, xmppchat)); }, converse));
it("are ordered according to status: online, busy, away, unavailable, offline", $.proxy(function () { it("are ordered according to status: online, busy, away, unavailable, offline", $.proxy(function () {
var contacts = this.rosterview.$el.find('dd.current-xmpp-contact'); var contacts = this.rosterview.$el.find('dd.current-xmpp-contact');
...@@ -287,17 +290,17 @@ ...@@ -287,17 +290,17 @@
for (i=12; i<cur_names.length; i++) { for (i=12; i<cur_names.length; i++) {
expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('offline'); expect($(contacts[i]).attr('class').split(' ',1)[0]).toEqual('offline');
} }
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("Requesting Contacts", $.proxy(function () { describe("Requesting Contacts", $.proxy(function () {
// by default the dts are hidden from css class and only later they will be hidden // by default the dts are hidden from css class and only later they will be hidden
// by jQuery therefore for the first check we will see if visible instead of none // by jQuery therefore for the first check we will see if visible instead of none
it("do not have a heading if there aren't any", $.proxy(function () { it("do not have a heading if there aren't any", $.proxy(function () {
expect(this.rosterview.$el.find('dt#xmpp-contact-requests').is(':visible')).toEqual(false); expect(this.rosterview.$el.find('dt#xmpp-contact-requests').is(':visible')).toEqual(false);
}, xmppchat)); }, converse));
it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () { it("can be added to the roster and they will be sorted alphabetically", $.proxy(function () {
var i, t; var i, t;
...@@ -319,11 +322,11 @@ ...@@ -319,11 +322,11 @@
// be opened. // be opened.
expect(this.showControlBox).toHaveBeenCalled(); expect(this.showControlBox).toHaveBeenCalled();
} }
}, xmppchat)); }, converse));
it("will have their own heading once they have been added", $.proxy(function () { it("will have their own heading once they have been added", $.proxy(function () {
expect(this.rosterview.$el.find('dt#xmpp-contact-requests').css('display')).toEqual('block'); expect(this.rosterview.$el.find('dt#xmpp-contact-requests').css('display')).toEqual('block');
}, xmppchat)); }, converse));
it("can have their requests accepted by the user", $.proxy(function () { it("can have their requests accepted by the user", $.proxy(function () {
// TODO: Testing can be more thorough here, the user is // TODO: Testing can be more thorough here, the user is
...@@ -338,7 +341,7 @@ ...@@ -338,7 +341,7 @@
accept_button.click(); accept_button.click();
expect(view.acceptRequest).toHaveBeenCalled(); expect(view.acceptRequest).toHaveBeenCalled();
expect(this.connection.roster.authorize).toHaveBeenCalled(); expect(this.connection.roster.authorize).toHaveBeenCalled();
}, xmppchat)); }, converse));
it("can have their requests denied by the user", $.proxy(function () { it("can have their requests denied by the user", $.proxy(function () {
var jid = req_names.sort()[1].replace(' ','.').toLowerCase() + '@localhost'; var jid = req_names.sort()[1].replace(' ','.').toLowerCase() + '@localhost';
...@@ -354,8 +357,8 @@ ...@@ -354,8 +357,8 @@
expect(this.connection.roster.unauthorize).toHaveBeenCalled(); expect(this.connection.roster.unauthorize).toHaveBeenCalled();
// There should now be one less contact // There should now be one less contact
expect(this.roster.length).toEqual(num_contacts-1); expect(this.roster.length).toEqual(num_contacts-1);
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("All Contacts", $.proxy(function () { describe("All Contacts", $.proxy(function () {
...@@ -384,7 +387,7 @@ ...@@ -384,7 +387,7 @@
expect(_.isEqual(new_attrs.sort(), old_attrs.sort())).toEqual(true); expect(_.isEqual(new_attrs.sort(), old_attrs.sort())).toEqual(true);
} }
this.rosterview.render(); this.rosterview.render();
}, xmppchat)); }, converse));
afterEach($.proxy(function () { afterEach($.proxy(function () {
// Contacts retrieved from localStorage have chat_status of // Contacts retrieved from localStorage have chat_status of
...@@ -396,12 +399,24 @@ ...@@ -396,12 +399,24 @@
view = this.rosterview.rosteritemviews[jid]; view = this.rosterview.rosteritemviews[jid];
view.model.set('chat_status', 'online'); view.model.set('chat_status', 'online');
} }
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("The 'Add Contact' widget", $.proxy(function () {
it("opens up an add form when you click on it", $.proxy(function () {
var panel = this.chatboxesview.views.controlbox.contactspanel;
spyOn(panel, 'toggleContactForm').andCallThrough();
panel.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
panel.$el.find('a.toggle-xmpp-contact-form').click();
expect(panel.toggleContactForm).toHaveBeenCalled();
// XXX: Awaiting more tests, close it again for now...
panel.$el.find('a.toggle-xmpp-contact-form').click();
}, converse));
}, converse));
describe("A Chatbox", $.proxy(function () { describe("A Chatbox", $.proxy(function () {
it("is created when you click on a roster item", $.proxy(function () { it("is created when you click on a roster item", $.proxy(function () {
var i, $el, click, jid, view; var i, $el, click, jid, view;
// showControlBox was called earlier, so the controlbox is // showControlBox was called earlier, so the controlbox is
...@@ -419,7 +434,7 @@ ...@@ -419,7 +434,7 @@
expect(view.openChat).toHaveBeenCalled(); expect(view.openChat).toHaveBeenCalled();
expect(this.chatboxes.length).toEqual(i+2); expect(this.chatboxes.length).toEqual(i+2);
} }
}, xmppchat)); }, converse));
it("can be saved to, and retrieved from, localStorage", $.proxy(function () { it("can be saved to, and retrieved from, localStorage", $.proxy(function () {
// We instantiate a new ChatBoxes collection, which by default // We instantiate a new ChatBoxes collection, which by default
...@@ -439,7 +454,7 @@ ...@@ -439,7 +454,7 @@
expect(_.isEqual(new_attrs, old_attrs)).toEqual(true); expect(_.isEqual(new_attrs, old_attrs)).toEqual(true);
} }
this.rosterview.render(); this.rosterview.render();
}, xmppchat)); }, converse));
it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", $.proxy(function () { it("can be closed again by clicking a DOM element with class 'close-chatbox-button'", $.proxy(function () {
var chatbox, view, $el, var chatbox, view, $el,
...@@ -452,7 +467,7 @@ ...@@ -452,7 +467,7 @@
view.$el.find('.close-chatbox-button').click(); view.$el.find('.close-chatbox-button').click();
expect(view.closeChat).toHaveBeenCalled(); expect(view.closeChat).toHaveBeenCalled();
} }
}, xmppchat)); }, converse));
it("will be removed from localStorage when closed", $.proxy(function () { it("will be removed from localStorage when closed", $.proxy(function () {
var newchatboxes = new this.ChatBoxes(); var newchatboxes = new this.ChatBoxes();
...@@ -465,7 +480,7 @@ ...@@ -465,7 +480,7 @@
// Lets open the controlbox again, purely for visual feedback // Lets open the controlbox again, purely for visual feedback
open_controlbox(); open_controlbox();
}, xmppchat)); }, converse));
describe("A Chat Message", $.proxy(function () { describe("A Chat Message", $.proxy(function () {
it("can be received which will open a chatbox and be displayed inside it", $.proxy(function () { it("can be received which will open a chatbox and be displayed inside it", $.proxy(function () {
...@@ -473,7 +488,7 @@ ...@@ -473,7 +488,7 @@
var sender_jid = cur_names[0].replace(' ','.').toLowerCase() + '@localhost'; var sender_jid = cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
msg = $msg({ msg = $msg({
from: sender_jid, from: sender_jid,
to: this.bare_jid, to: this.connection.jid,
type: 'chat', type: 'chat',
id: (new Date()).getTime() id: (new Date()).getTime()
}).c('body').t(message).up() }).c('body').t(message).up()
...@@ -488,7 +503,7 @@ ...@@ -488,7 +503,7 @@
// messageReceived is a handler for received XMPP // messageReceived is a handler for received XMPP
// messages // messages
this.chatboxes.messageReceived(msg); this.chatboxes.messageReceived(msg);
}, xmppchat)); }, converse));
waits(500); waits(500);
runs($.proxy(function () { runs($.proxy(function () {
// Since we didn't already have an open chatbox, one // Since we didn't already have an open chatbox, one
...@@ -514,8 +529,8 @@ ...@@ -514,8 +529,8 @@
// chatbox in the DOM // chatbox in the DOM
var txt = chatboxview.$el.find('.chat-content').find('.chat-message').find('.chat-message-content').text(); var txt = chatboxview.$el.find('.chat-content').find('.chat-message').find('.chat-message-content').text();
expect(txt).toEqual(message); expect(txt).toEqual(message);
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
it("can be sent from a chatbox, and will appear inside it", $.proxy(function () { it("can be sent from a chatbox, and will appear inside it", $.proxy(function () {
var contact_jid = cur_names[0].replace(' ','.').toLowerCase() + '@localhost'; var contact_jid = cur_names[0].replace(' ','.').toLowerCase() + '@localhost';
...@@ -528,9 +543,9 @@ ...@@ -528,9 +543,9 @@
expect(view.model.messages.length, 2); expect(view.model.messages.length, 2);
var txt = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content').text(); var txt = view.$el.find('.chat-content').find('.chat-message').last().find('.chat-message-content').text();
expect(txt).toEqual(message); expect(txt).toEqual(message);
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
describe("The Controlbox Tabs", $.proxy(function () { describe("The Controlbox Tabs", $.proxy(function () {
it("consist of two tabs, 'Contacts' and 'ChatRooms', of which 'Contacts' is by default visible", $.proxy(function () { it("consist of two tabs, 'Contacts' and 'ChatRooms', of which 'Contacts' is by default visible", $.proxy(function () {
...@@ -541,7 +556,7 @@ ...@@ -541,7 +556,7 @@
expect($panels.children().first().is(':visible')).toBe(true); expect($panels.children().first().is(':visible')).toBe(true);
expect($panels.children().last().attr('id')).toBe('chatrooms'); expect($panels.children().last().attr('id')).toBe('chatrooms');
expect($panels.children().last().is(':visible')).toBe(false); expect($panels.children().last().is(':visible')).toBe(false);
}, xmppchat)); }, converse));
describe("The Chatrooms Panel", $.proxy(function () { describe("The Chatrooms Panel", $.proxy(function () {
...@@ -562,7 +577,7 @@ ...@@ -562,7 +577,7 @@
expect($chatrooms.is(':visible')).toBe(true); expect($chatrooms.is(':visible')).toBe(true);
expect(cbview.switchTab).toHaveBeenCalled(); expect(cbview.switchTab).toHaveBeenCalled();
}); });
}, xmppchat)); }, converse));
it("contains a form through which a new chatroom can be created", $.proxy(function () { it("contains a form through which a new chatroom can be created", $.proxy(function () {
var roomspanel = this.chatboxesview.views.controlbox.roomspanel; var roomspanel = this.chatboxesview.views.controlbox.roomspanel;
...@@ -582,13 +597,9 @@ ...@@ -582,13 +597,9 @@
waits('250'); waits('250');
runs($.proxy(function () { runs($.proxy(function () {
expect($('.chatroom').length).toBe(1); // There should now be an open chatroom expect($('.chatroom').length).toBe(1); // There should now be an open chatroom
}, xmppchat)); }, converse));
}, xmppchat)); }, converse));
}, converse));
}, converse));
}, xmppchat)); }, converse));
}, xmppchat));
}, xmppchat));
})); }));
...@@ -29,5 +29,11 @@ ...@@ -29,5 +29,11 @@
</a> </a>
</div> </div>
</div> </div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">try { var pageTracker = _gat._getTracker("UA-2128260-8"); pageTracker._trackPageview(); } catch(err) {}</script>
</body> </body>
</html> </html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment