Big refactoring.
Removed ControlBox model, and instead only create ChatBox models inside ChatBoxes collection (the Controlbox is now also a ChatBox). This enables us to use backbone.localStorage for saving open chatboxes (saving and fetching currently not implemented). createChatBox now doesn't return a ChatBoxView instance anymore. In the case where a view was needed (to append a message), we create the message on the ChatBox and let the view update via an event trigger. This is much more Backbonic ;) Also created a Message model. This will most likely enable us to in the future also store messages via backbone.localStorage.
This commit is contained in:
parent
2fe7164df6
commit
48e4ed271e
264
converse.js
264
converse.js
@ -99,6 +99,12 @@
|
||||
return String(str).indexOf(needle) !== -1;
|
||||
};
|
||||
|
||||
xmppchat.autoLink = function (text) {
|
||||
// Convert URLs into hyperlinks
|
||||
var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
|
||||
return text.replace(re, '<a target="_blank" href="$1">$1</a>');
|
||||
};
|
||||
|
||||
xmppchat.toISOString = function (date) {
|
||||
var pad;
|
||||
if (typeof date.toISOString !== 'undefined') {
|
||||
@ -283,17 +289,73 @@
|
||||
}
|
||||
});
|
||||
|
||||
xmppchat.Message = Backbone.Model.extend();
|
||||
|
||||
xmppchat.Messages = Backbone.Collection.extend({
|
||||
model: xmppchat.Message
|
||||
});
|
||||
|
||||
xmppchat.ChatBox = Backbone.Model.extend({
|
||||
messages: new xmppchat.Messages(),
|
||||
initialize: function () {
|
||||
this.set({
|
||||
'user_id' : Strophe.getNodeFromJid(this.get('jid')),
|
||||
'box_id' : hex_sha1(this.get('jid')),
|
||||
'fullname' : this.get('fullname'),
|
||||
'url': this.get('url'),
|
||||
'image_type': this.get('image_type'),
|
||||
'image_src': this.get('image_src')
|
||||
});
|
||||
}
|
||||
if (this.get('box_id') !== 'controlbox') {
|
||||
this.set({
|
||||
'user_id' : Strophe.getNodeFromJid(this.get('jid')),
|
||||
'box_id' : hex_sha1(this.get('jid')),
|
||||
'fullname' : this.get('fullname'),
|
||||
'url': this.get('url'),
|
||||
'image_type': this.get('image_type'),
|
||||
'image_src': this.get('image_src')
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
messageReceived: function (message) {
|
||||
var $message = $(message),
|
||||
body = xmppchat.autoLink($message.children('body').text()),
|
||||
from = Strophe.getBareJidFromJid($message.attr('from')),
|
||||
composing = $message.find('composing'),
|
||||
delayed = $message.find('delay').length > 0,
|
||||
fullname = this.get('fullname').split(' ')[0],
|
||||
stamp, time;
|
||||
|
||||
|
||||
if (!body) {
|
||||
if (composing.length) {
|
||||
this.messages.add({
|
||||
fullname: fullname,
|
||||
sender: 'them',
|
||||
delayed: delayed,
|
||||
composing: composing.length
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (delayed) {
|
||||
stamp = $message.find('delay').attr('stamp');
|
||||
time = (new Date(stamp)).toLocaleTimeString().substring(0,5);
|
||||
} else {
|
||||
time = (new Date()).toLocaleTimeString().substring(0,5);
|
||||
}
|
||||
|
||||
if (from == xmppchat.connection.bare_jid) {
|
||||
this.messages.add({
|
||||
fullname: 'me',
|
||||
sender: 'me',
|
||||
delayed: delayed,
|
||||
time: time,
|
||||
message: body
|
||||
});
|
||||
} else {
|
||||
this.messages.add({
|
||||
fullname: fullname,
|
||||
sender: 'them',
|
||||
delayed: delayed,
|
||||
time: time,
|
||||
message: body
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
xmppchat.ChatBoxView = Backbone.View.extend({
|
||||
@ -318,12 +380,6 @@
|
||||
'<span class="chat-message-content">{{message}}</span>' +
|
||||
'</div>'),
|
||||
|
||||
autoLink: function (text) {
|
||||
// Convert URLs into hyperlinks
|
||||
var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
|
||||
return text.replace(re, '<a target="_blank" href="$1">$1</a>');
|
||||
},
|
||||
|
||||
appendMessage: function (message) {
|
||||
var now = new Date(),
|
||||
time = now.toLocaleTimeString().substring(0,5),
|
||||
@ -338,7 +394,7 @@
|
||||
$chat_content.append($('<div class="chat-date"></div>').text(now.toString().substring(0,15)));
|
||||
}
|
||||
}
|
||||
message = this.autoLink(message);
|
||||
message = xmppchat.autoLink(message);
|
||||
// TODO use minutes logic or remove it
|
||||
if (minutes.length==1) {minutes = '0'+minutes;}
|
||||
$chat_content.find('div.chat-event').remove();
|
||||
@ -360,54 +416,25 @@
|
||||
},
|
||||
|
||||
messageReceived: function (message) {
|
||||
/* XXX: event.mtype should be 'xhtml' for XHTML-IM messages,
|
||||
but I only seem to get 'text'.
|
||||
*/
|
||||
var $message = $(message);
|
||||
var body = this.autoLink($message.children('body').text()),
|
||||
from = Strophe.getBareJidFromJid($message.attr('from')),
|
||||
to = $message.attr('to'),
|
||||
composing = $message.find('composing'),
|
||||
$chat_content = this.$el.find('.chat-content'),
|
||||
delayed = $message.find('delay').length > 0,
|
||||
fullname = this.model.get('fullname'),
|
||||
time, stamp, username, sender;
|
||||
var $chat_content = this.$el.find('.chat-content');
|
||||
if (xmppchat.xmppstatus.getStatus() === 'offline') {
|
||||
// only update the UI if the user is not offline
|
||||
return;
|
||||
}
|
||||
if (!body) {
|
||||
if (composing.length) {
|
||||
this.insertStatusNotification(fullname+' '+'is typing');
|
||||
return;
|
||||
}
|
||||
if (message.get('composing')) {
|
||||
this.insertStatusNotification(message.get('fullname')+' '+'is typing');
|
||||
return;
|
||||
} else {
|
||||
if (from == xmppchat.connection.bare_jid) {
|
||||
// I am the sender, so this must be a forwarded message...
|
||||
$chat_content.find('div.chat-event').remove();
|
||||
username = 'me';
|
||||
sender = 'me';
|
||||
} else {
|
||||
xmppchat.storage.addMessage(from, body, 'from');
|
||||
$chat_content.find('div.chat-event').remove();
|
||||
username = fullname.split(' ')[0];
|
||||
sender = 'them';
|
||||
}
|
||||
if (delayed) {
|
||||
// XXX: Test properly (for really old messages we somehow need to show
|
||||
// their date as well)
|
||||
stamp = $message.find('delay').attr('stamp');
|
||||
time = (new Date(stamp)).toLocaleTimeString().substring(0,5);
|
||||
} else {
|
||||
time = (new Date()).toLocaleTimeString().substring(0,5);
|
||||
}
|
||||
// xmppchat.storage.addMessage(from, body, 'from');
|
||||
$chat_content.find('div.chat-event').remove();
|
||||
// TODO use toJSON here
|
||||
$chat_content.append(
|
||||
this.message_template({
|
||||
'sender': sender,
|
||||
'time': time,
|
||||
'message': body,
|
||||
'username': username,
|
||||
'extra_classes': delayed && 'delayed' || ''
|
||||
'sender': message.get('sender'),
|
||||
'time': message.get('time'),
|
||||
'message': message.get('message'),
|
||||
'username': message.get('fullname'),
|
||||
'extra_classes': message.get('delayed') && 'delayed' || ''
|
||||
}));
|
||||
$chat_content.scrollTop($chat_content[0].scrollHeight);
|
||||
}
|
||||
@ -441,7 +468,7 @@
|
||||
$content.append($('<div class="chat-date"></div>').text(this_date.toString().substring(0,15)));
|
||||
}
|
||||
}
|
||||
msg = this.autoLink(String(msg).replace(/(.*?\s.*?\s)/, ''));
|
||||
msg = xmppchat.autoLink(String(msg).replace(/(.*?\s.*?\s)/, ''));
|
||||
if (msg_array[1] == 'to') {
|
||||
$content.append(
|
||||
this.message_template({
|
||||
@ -565,6 +592,10 @@
|
||||
initialize: function (){
|
||||
$('body').append(this.$el.hide());
|
||||
|
||||
this.model.messages.on('add', function (item) {
|
||||
this.messageReceived(item);
|
||||
}, this);
|
||||
|
||||
xmppchat.roster.on('change', function (item, changed) {
|
||||
var fullname = this.model.get('fullname'),
|
||||
chat_status = item.get('chat_status');
|
||||
@ -801,6 +832,7 @@
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
xmppchat.ControlBox = xmppchat.ChatBox.extend({
|
||||
initialize: function () {
|
||||
this.set({
|
||||
@ -808,6 +840,7 @@
|
||||
});
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
xmppchat.ControlBoxView = xmppchat.ChatBoxView.extend({
|
||||
// XXX: Options for the (still to be done) 'settings' tab:
|
||||
@ -822,7 +855,7 @@
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
$('body').append(this.$el.hide());
|
||||
// Override the one in ChatBoxView
|
||||
},
|
||||
|
||||
template: _.template(
|
||||
@ -854,10 +887,12 @@
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var that = this;
|
||||
this.$el.hide('fast', function () {
|
||||
$(this).html(that.template(that.model.toJSON()));
|
||||
});
|
||||
this.$el.html(this.template(this.model.toJSON()));
|
||||
this.$el.appendTo(xmppchat.chatboxesview.$el);
|
||||
// Add login panel if the user still has to authenticate
|
||||
if (!xmppchat.username) {
|
||||
this.loginpanel = new xmppchat.LoginPanel().render();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
@ -1040,7 +1075,7 @@
|
||||
'time': (new Date()).toLocaleTimeString().substring(0,5),
|
||||
'message': body,
|
||||
'username': sender,
|
||||
'extra_classes': ($message.find('delay').length > 0) && 'delayed' || ''
|
||||
'extra_classes': ($message.find('delay').length > 0) && 'delayed' || '',
|
||||
}));
|
||||
} else {
|
||||
$chat_content.append(
|
||||
@ -1147,20 +1182,14 @@
|
||||
},
|
||||
|
||||
createChatBox: function (data) {
|
||||
var jid = data['jid'];
|
||||
var box = new xmppchat.ChatBox({
|
||||
'id': jid,
|
||||
'jid': jid,
|
||||
'fullname': data['fullname'],
|
||||
'image_type': data['image_type'],
|
||||
'image': data['image'],
|
||||
'url': data['url'],
|
||||
});
|
||||
var view = new xmppchat.ChatBoxView({model: box});
|
||||
this.views[jid] = view.render();
|
||||
view.$el.appendTo(this.$el);
|
||||
this.options.model.add(box);
|
||||
return view;
|
||||
return this.options.model.add({
|
||||
'id': data['jid'],
|
||||
'jid': data['jid'],
|
||||
'fullname': data['fullname'],
|
||||
'image_type': data['image_type'],
|
||||
'image': data['image'],
|
||||
'url': data['url'],
|
||||
});
|
||||
},
|
||||
|
||||
closeChat: function (jid) {
|
||||
@ -1170,6 +1199,17 @@
|
||||
}
|
||||
},
|
||||
|
||||
openControlBox: function () {
|
||||
if (this.model.get('controlbox')) {
|
||||
this.showChat('controlbox');
|
||||
} else {
|
||||
this.options.model.add({
|
||||
id: 'controlbox',
|
||||
box_id: 'controlbox'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
openChat: function (roster_item) {
|
||||
var jid = roster_item.get('jid');
|
||||
jid = Strophe.getBareJidFromJid(jid);
|
||||
@ -1214,7 +1254,7 @@
|
||||
}
|
||||
var from = Strophe.getBareJidFromJid(message_from),
|
||||
to = Strophe.getBareJidFromJid($message.attr('to')),
|
||||
view, resource;
|
||||
view, resource, chatboxes;
|
||||
if (from == xmppchat.connection.bare_jid) {
|
||||
// I am the sender, so this must be a forwarded message...
|
||||
partner_jid = to;
|
||||
@ -1229,31 +1269,28 @@
|
||||
xmppchat.getVCard(
|
||||
partner_jid,
|
||||
$.proxy(function (jid, fullname, img, img_type, url) {
|
||||
view = this.createChatBox({
|
||||
// FIXME: We don't get the view from createChatBox
|
||||
// anymore.
|
||||
// Instead, we should trigger an event on the model
|
||||
chatboxes = this.createChatBox({
|
||||
'jid': jid,
|
||||
'fullname': fullname,
|
||||
'image': img,
|
||||
'image_type': img_type,
|
||||
'url': url,
|
||||
})
|
||||
view.messageReceived(message);
|
||||
chatboxes.get(jid).messageReceived(message);
|
||||
xmppchat.roster.addResource(partner_jid, resource);
|
||||
}, this),
|
||||
$.proxy(function () {
|
||||
// Error occured while fetching vcard
|
||||
// # TODO: call the function above
|
||||
console.log("An error occured while fetching vcard");
|
||||
view = this.createChatBox({
|
||||
'jid': jid,
|
||||
'fullname': jid,
|
||||
})
|
||||
view.messageReceived(message);
|
||||
xmppchat.roster.addResource(partner_jid, resource);
|
||||
}, this));
|
||||
return true;
|
||||
} else if (!view.isVisible()) {
|
||||
this.showChat(partner_jid);
|
||||
}
|
||||
view.messageReceived(message);
|
||||
view.model.messageReceived(message);
|
||||
xmppchat.roster.addResource(partner_jid, resource);
|
||||
return true;
|
||||
},
|
||||
@ -1266,39 +1303,33 @@
|
||||
controlbox.roomspanel = new xmppchat.RoomsPanel().render();
|
||||
// Add the roster
|
||||
xmppchat.roster = new xmppchat.RosterItems();
|
||||
xmppchat.roster.localStorage = new Backbone.LocalStorage(hex_sha1(xmppchat.connection.bare_jid));
|
||||
xmppchat.roster.localStorage = new Backbone.LocalStorage(
|
||||
hex_sha1('converse.rosteritems-'+xmppchat.connection.bare_jid));
|
||||
xmppchat.rosterview = new xmppchat.RosterView({'model':xmppchat.roster});
|
||||
xmppchat.rosterview.$el.appendTo(controlbox.contactspanel.$el);
|
||||
xmppchat.roster.fetch({add: true}); // Gets the cached roster items from localstorage
|
||||
xmppchat.rosterview.initialSort();
|
||||
// TODO: we're going to use localStorage here
|
||||
// Restore previously open chatboxes
|
||||
this.restoreOpenChats();
|
||||
// this.restoreOpenChats();
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
this.options.model.on("add", function (item) {
|
||||
// The controlbox added automatically, but we don't show it
|
||||
// automatically (only when it was open before page load or
|
||||
// upon a click).
|
||||
if ((item.get('id') != 'controlbox') || (!xmppchat.username)) {
|
||||
this.showChat(item.get('id'));
|
||||
}
|
||||
}, this);
|
||||
this.views = {};
|
||||
// Add the controlbox view
|
||||
this.views.controlbox = new xmppchat.ControlBoxView({
|
||||
model: new xmppchat.ControlBox({'id':'controlbox', 'jid':'controlbox'})
|
||||
}).render();
|
||||
|
||||
this.views.controlbox.$el.appendTo(this.$el);
|
||||
// Add login panel if the user still has to authenticate
|
||||
if (!xmppchat.username) {
|
||||
this.views.controlbox.loginpanel = new xmppchat.LoginPanel().render();
|
||||
}
|
||||
// Rebind events (necessary for click events on tabs inserted via the panels)
|
||||
this.views.controlbox.delegateEvents();
|
||||
// Add the controlbox model to this collection (will trigger showChat)
|
||||
this.options.model.add(this.views.controlbox.options.model);
|
||||
this.options.model.on("add", function (item) {
|
||||
var view;
|
||||
if (item.get('box_id') === 'controlbox') {
|
||||
view = new xmppchat.ControlBoxView({model: item});
|
||||
} else {
|
||||
view = new xmppchat.ChatBoxView({model: item});
|
||||
}
|
||||
this.views[item.get('id')] = view.render();
|
||||
this.showChat(item.get('id'));
|
||||
}, this);
|
||||
/*
|
||||
// Rebind events (necessary for click events on tabs inserted via the panels)
|
||||
this.views.controlbox.delegateEvents();
|
||||
*/
|
||||
}
|
||||
});
|
||||
|
||||
@ -2115,15 +2146,16 @@
|
||||
this.fullname = chatdata.attr('fullname');
|
||||
this.auto_subscribe = chatdata.attr('auto_subscribe') === "True" || false;
|
||||
|
||||
this.chatboxes = new this.ChatBoxes();
|
||||
this.chatboxesview = new this.ChatBoxesView({
|
||||
model: new this.ChatBoxes()
|
||||
model: this.chatboxes
|
||||
});
|
||||
$toggle.bind('click', $.proxy(function (e) {
|
||||
e.preventDefault();
|
||||
if ($("div#controlbox").is(':visible')) {
|
||||
this.chatboxesview.closeChat('controlbox');
|
||||
} else {
|
||||
this.chatboxesview.showChat('controlbox');
|
||||
this.chatboxesview.openControlBox();
|
||||
}
|
||||
}, this));
|
||||
|
||||
@ -2151,6 +2183,8 @@
|
||||
this.connection.muc_domain = 'conference.' + this.connection.domain;
|
||||
this.storage = new this.ClientStorage(hex_sha1(this.connection.bare_jid));
|
||||
|
||||
this.chatboxes.localStorage = new Backbone.LocalStorage(
|
||||
hex_sha1('converse.chatboxes-'+xmppchat.connection.bare_jid));
|
||||
this.chatboxesview.onConnected();
|
||||
|
||||
this.connection.addHandler(
|
||||
|
Loading…
Reference in New Issue
Block a user