'),
appendMessage: function (message) {
var time,
now = new Date(),
minutes = now.getMinutes().toString(),
list,
$chat_content;
message = message.replace(//g,">").replace(/\"/g,""");
list = message.match(/\b(http:\/\/www\.\S+\.\w+|www\.\S+\.\w+|http:\/\/(?=[^w]){3}\S+[\.:]\S+)[^ ]+\b/g);
if (list) {
for (i = 0; i < list.length; i++) {
message = message.replace(list[i], ""+ list[i] + "" );
}
}
if (minutes.length==1) {minutes = '0'+minutes;}
time = now.toLocaleTimeString().substring(0,5);
$chat_content = $(this.el).find('.chat-content');
$chat_content.append(this.message_template({
'sender': 'me',
'time': time,
'message': message,
'username': 'me',
'extra_classes': ''
}));
$chat_content.scrollTop($chat_content[0].scrollHeight);
},
insertStatusNotification: function (message) {
var $chat_content = this.$el.find('.chat-content');
$chat_content.find('div.chat-event').remove().end()
.append($('').text(this.model.get('user_id')+' '+message));
$chat_content.scrollTop($chat_content[0].scrollHeight);
},
messageReceived: function (message) {
/* XXX: event.mtype should be 'xhtml' for XHTML-IM messages,
but I only seem to get 'text'.
XXX: Some messages might be delayed, we must get the time from the event.
*/
var body = $(message).children('body').text(),
jid = $(message).attr('from'),
composing = $(message).find('composing'),
$chat_content = $(this.el).find('.chat-content'),
user_id = Strophe.getNodeFromJid(jid);
if (!body) {
if (composing.length > 0) {
this.insertStatusNotification('is typing');
return;
}
} else {
// TODO: ClientStorage
xmppchat.Messages.ClientStorage.addMessage(jid, body, 'from');
if (xmppchat.xmppstatus.getOwnStatus() === 'offline') {
// only update the UI if the user is not offline
return;
}
$chat_content.find('div.chat-event').remove();
$chat_content.append(
this.message_template({
'sender': 'them',
'time': (new Date()).toLocaleTimeString().substring(0,5),
'message': body.replace(/ /g, ""),
'username': user_id,
'extra_classes': ($(message).find('delay').length > 0) && 'delayed' || ''
}));
$chat_content.scrollTop($chat_content[0].scrollHeight);
}
},
insertClientStoredMessages: function () {
var that = this;
xmppchat.Messages.getMessages(this.model.get('jid'), function (msgs) {
var $content = that.$el.find('.chat-content');
for (var i=0; i<_.size(msgs); i++) {
var msg = msgs[i],
msg_array = msg.split(' ', 2),
date = msg_array[0];
if (msg_array[1] == 'to') {
$content.append(
that.message_template({
'sender': 'me',
'time': new Date(Date.parse(date)).toLocaleTimeString().substring(0,5),
'message': String(msg).replace(/(.*?\s.*?\s)/, ''),
'username': 'me',
'extra_classes': 'delayed'
}));
} else {
$content.append(
that.message_template({
'sender': 'them',
'time': new Date(Date.parse(date)).toLocaleTimeString().substring(0,5),
'message': String(msg).replace(/(.*?\s.*?\s)/, ''),
'username': that.model.get('user_id'),
'extra_classes': 'delayed'
}));
}
}
});
},
sendMessage: function (text) {
// TODO: Also send message to all my own connected resources, so that
// they can display it as well....
// TODO: Look in ChatPartners to see what resources we have for the recipient.
// if we have one resource, we sent to only that resources, if we have multiple
// we send to the bare jid.
var bare_jid = this.model.get('jid');
var message = $msg({to: bare_jid, type: 'chat'})
.c('body').t(text).up()
.c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'});
xmppchat.connection.send(message);
xmppchat.Messages.ClientStorage.addMessage(bare_jid, text, 'to');
this.appendMessage(text);
},
keyPressed: function (ev) {
var $textarea = $(ev.target),
message,
notify,
composing,
that = this;
if(ev.keyCode == 13) {
message = $textarea.val();
message = message.replace(/^\s+|\s+jQuery/g,"");
$textarea.val('').focus();
if (message !== '') {
this.sendMessage(message);
}
$(this.el).data('composing', false);
} else {
composing = $(this.el).data('composing');
if (!composing) {
notify = $msg({'to':this.model.get('jid'), 'type': 'chat'})
.c('composing', {'xmlns':'http://jabber.org/protocol/chatstates'});
xmppchat.connection.send(notify);
$(this.el).data('composing', true);
}
}
},
addChatToCookie: function () {
var cookie = jQuery.cookie('chats-open-'+xmppchat.username),
jid = this.model.get('jid'),
new_cookie,
open_chats = [];
if (cookie) {
open_chats = cookie.split('|');
}
if (!_.has(open_chats, jid)) {
// Update the cookie if this new chat is not yet in it.
open_chats.push(jid);
new_cookie = open_chats.join('|');
jQuery.cookie('chats-open-'+xmppchat.username, new_cookie, {path: '/'});
console.log('updated cookie = ' + new_cookie + '\n');
}
},
removeChatFromCookie: function () {
var cookie = jQuery.cookie('chats-open-'+xmppchat.username),
open_chats = [],
new_chats = [];
if (cookie) {
open_chats = cookie.split('|');
}
for (var i=0; i < open_chats.length; i++) {
if (open_chats[i] != this.model.get('jid')) {
new_chats.push(open_chats[i]);
}
}
if (new_chats.length) {
jQuery.cookie('chats-open-'+xmppchat.username, new_chats.join('|'), {path: '/'});
}
else {
jQuery.cookie('chats-open-'+xmppchat.username, null, {path: '/'});
}
},
closeChat: function () {
var that = this;
$('#'+this.model.get('box_id')).hide('fast', function () {
that.removeChatFromCookie(that.model.get('id'));
});
},
initialize: function (){
$('body').append($(this.el).hide());
xmppchat.roster.on('change', function (item, changed) {
if (_.has(changed.changes, 'status')) {
if (this.$el.is(':visible')) {
if (item.get('status') === 'offline') {
this.insertStatusNotification('has gone offline');
} else if (item.get('status') === 'away') {
this.insertStatusNotification('has gone away');
} else if (item.get('status') === 'busy') {
this.insertStatusNotification('is busy');
} else if (item.get('status') === 'online') {
this.$el.find('div.chat-event').remove();
}
}
}
}, this);
},
template: _.template(
'
'),
initialize: function () {
xmppchat.connection.muc.join(
this.model.get('jid'),
this.model.get('nick'),
$.proxy(this.onMessage, this),
$.proxy(this.onPresence, this),
$.proxy(this.onRoomMessage, this));
},
onPresence: function (presence, room) {
var nick = room.nick,
from = $(presence).attr('from'),
participants = this.model.get('participants');
if (!participants[nick] && $(presence).attr('type') !== 'unavailable') {
// add to participants list
participants[nick] = $(presence).attr('jid');
this.model.set({'participants':participants});
}
if ($(presence).attr('type') !== 'error') {
// check for status 110 to see if it's our own presence
if ($(presence).find("status[code='110']").length > 0) {
// check if server changed our nick
if ($(presence).find("status[code='210']").length > 0) {
this.model.set({'nick': Strophe.getResourceFromJid(from)});
}
}
}
this.$el.find('.participant-list').append('
' + nick + '
');
},
onMessage: function (x,y,z) {
alert('onMessage');
},
onRoster: function (x,y,z) {
alert('onRoster');
},
render: function () {
$(this.el).attr('id', this.model.get('box_id'));
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
});
xmppchat.ChatBoxes = Backbone.Collection.extend();
xmppchat.ChatBoxesView = Backbone.View.extend({
el: '#collective-xmpp-chat-data',
restoreOpenChats: function () {
var cookie = jQuery.cookie('chats-open-'+xmppchat.username),
open_chats = [];
jQuery.cookie('chats-open-'+xmppchat.username, null, {path: '/'});
if (cookie) {
open_chats = cookie.split('|');
if (_.indexOf(open_chats, 'online-users-container') != -1) {
this.renderChat('online-users-container');
}
for (var i=0; i").dialog({
title: 'Are you sure you want to remove this contact?',
dialogClass: 'remove-xmpp-contact-dialog',
resizable: false,
width: 200,
position: {
my: 'center',
at: 'center',
of: '#online-users-container'
},
modal: true,
buttons: {
"Remove": function() {
$(this).dialog( "close" );
xmppchat.connection.roster.unauthorize(that.model.get('jid'));
xmppchat.roster.remove(bare_jid);
xmppchat.connection.roster.remove(bare_jid);
},
"Cancel": function() {
$(this).dialog( "close" );
}
}
});
},
acceptRequest: function () {
xmppchat.connection.roster.authorize(this.model.get('jid'));
xmppchat.connection.roster.subscribe(this.model.get('jid'));
},
declineRequest: function () {
var that = this;
xmppchat.connection.roster.unauthorize(this.model.get('jid'));
that.trigger('decline-request', that.model);
},
template: _.template(
'<%= fullname %>' +
''),
request_template: _.template('<%= fullname %>' +
'' +
'' +
''),
render: function () {
var item = this.model,
ask = item.get('ask'),
that = this,
subscription = item.get('subscription');
$(this.el).addClass(item.get('status')).attr('id', 'online-users-'+item.get('user_id'));
if (ask === 'subscribe') {
this.$el.addClass('pending-xmpp-contact');
$(this.el).html(this.template(item.toJSON()));
} else if (ask === 'request') {
this.$el.addClass('requesting-xmpp-contact');
$(this.el).html(this.request_template(item.toJSON()));
this.$el.find('button.accept-xmpp-request').on('click', function (ev) {
ev.preventDefault();
that.acceptRequest();
});
this.$el.find('button.decline-xmpp-request').on('click', function (ev) {
ev.preventDefault();
that.declineRequest();
});
} else if (subscription === 'both') {
this.$el.addClass('current-xmpp-contact');
this.$el.html(this.template(item.toJSON()));
this.$el.find('a.open-chat').on('click', function (ev) {
ev.preventDefault();
that.openChat();
});
this.$el.find('a.remove-xmpp-contact').on('click', function (ev) {
ev.preventDefault();
that.removeContact();
});
}
return this;
},
initialize: function () {
this.options.model.on('change', function (item, changed) {
if (_.has(changed.changes, 'status')) {
$(this.el).attr('class', item.changed.status);
}
}, this);
}
});
xmppchat.Roster = (function (_, $, console) {
var ob = {},
Collection = Backbone.Collection.extend({
model: xmppchat.RosterItem,
stropheRoster: xmppchat.connection.roster,
initialize: function () {
this._connection = xmppchat.connection;
},
comparator : function (rosteritem) {
var status = rosteritem.get('status'),
rank = 4;
switch(status) {
case 'offline':
rank = 4;
break;
case 'unavailable':
rank = 3;
break;
case 'away':
rank = 2;
break;
case 'busy':
rank = 1;
break;
case 'online':
rank = 0;
break;
}
return rank;
},
isSelf: function (jid) {
return (Strophe.getBareJidFromJid(jid) === Strophe.getBareJidFromJid(xmppchat.connection.jid));
},
getRoster: function () {
return xmppchat.connection.roster.get();
},
getItem: function (id) {
return Backbone.Collection.prototype.get.call(this, id);
},
addRosterItem: function (jid, subscription, ask) {
var model = new xmppchat.RosterItem(jid, subscription, ask);
this.add(model);
},
addResource: function (bare_jid, resource) {
var item = this.getItem(bare_jid),
resources;
if (item) {
resources = item.get('resources');
if (_.indexOf(resources, resource) == -1) {
resources.push(resource);
item.set({'resources': resources});
}
} else {
item.set({'resources': [resource]});
}
},
removeResource: function (bare_jid, resource) {
var item = this.getItem(bare_jid),
resources,
idx;
if (item) {
resources = item.get('resources');
idx = _.indexOf(resources, resource);
if (idx !== -1) {
resources.splice(idx, 1);
item.set({'resources': resources});
return resources.length;
}
}
return 0;
},
clearResources: function (bare_jid) {
var item = this.getItem(bare_jid);
if (item) {
item.set({'resources': []});
}
},
getTotalResources: function (bare_jid) {
var item = this.getItem(bare_jid);
if (item) {
return _.size(item.get('resources'));
}
},
getNumOnlineContacts: function () {
var count = 0;
for (var i=0; iContact requests' +
'
My contacts
' +
'
Pending contacts
'),
render: function () {
this.$el.empty().html(this.template());
var models = this.model.sort().models,
children = $(this.el).children(),
my_contacts = this.$el.find('#xmpp-contacts').hide(),
contact_requests = this.$el.find('#xmpp-contact-requests').hide(),
pending_contacts = this.$el.find('#pending-xmpp-contacts').hide();
for (var i=0; i 0) {
h.show();
}
});
$('#online-count').text(this.model.getNumOnlineContacts());
}
});
var view = new View();
return view;
});
xmppchat.XMPPStatus = Backbone.Model.extend({
sendPresence: function (type) {
if (type === undefined) {
type = this.getOwnStatus() || 'online';
}
xmppchat.connection.send($pres({'type':type}));
},
getOwnStatus: function () {
return store.get(xmppchat.connection.bare_jid+'-xmpp-status');
},
setOwnStatus: function (value) {
this.sendPresence(value);
store.set(xmppchat.connection.bare_jid+'-xmpp-status', value);
}
});
xmppchat.XMPPStatusView = Backbone.View.extend({
el: "span#xmpp-status-holder",
events: {
"click #fancy-xmpp-status-select": "toggleOptions",
"click .dropdown dd ul li a": "setOwnStatus"
},
toggleOptions: function (ev) {
ev.preventDefault();
$(ev.target).parent().siblings('dd').find('ul').toggle('fast');
},
setOwnStatus: function (ev) {
ev.preventDefault();
var $el = $(ev.target).find('span'),
value = $el.text();
$(this.el).find(".dropdown dt a").html('I am ' + value).attr('class', value);
$(this.el).find(".dropdown dd ul").hide();
$(this.el).find("#source").val($($el).find("span.value").html());
this.model.setOwnStatus(value);
},
choose_template: _.template('
'),
initialize: function () {
var $select = $(this.el).find('select#select-xmpp-status'),
chat_status = this.model.getOwnStatus() || 'offline',
options = $('option', $select),
that = this;
$(this.el).html(this.choose_template({'chat_status': chat_status}));
// iterate through all the