Commit b111e60c authored by JC Brand's avatar JC Brand

Merge branch '0.6.x'

Conflicts:
	converse.js
parents 0752a0e2 fcc1f5ad
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
var converse = this; var converse = this;
// Constants // Constants
// ---------
var UNENCRYPTED = 0; var UNENCRYPTED = 0;
var UNVERIFIED= 1; var UNVERIFIED= 1;
var VERIFIED= 2; var VERIFIED= 2;
...@@ -54,7 +55,8 @@ ...@@ -54,7 +55,8 @@
ENTER: 13 ENTER: 13
}; };
// Default values // Default configuration values
// ----------------------------
this.allow_contact_requests = true; this.allow_contact_requests = true;
this.allow_muc = true; this.allow_muc = true;
this.allow_otr = true; this.allow_otr = true;
...@@ -72,11 +74,8 @@ ...@@ -72,11 +74,8 @@
this.xhr_custom_status = false; this.xhr_custom_status = false;
this.xhr_user_search = false; this.xhr_user_search = false;
this.callback = callback || function () {}; // Allow only whitelisted configuration attributes to be overwritten
_.extend(this, _.pick(settings, [
// Allow only the whitelisted settings attributes to be overwritten,
// nothing else.
whitelist = [
'allow_contact_requests', 'allow_contact_requests',
'allow_muc', 'allow_muc',
'allow_otr', 'allow_otr',
...@@ -98,9 +97,10 @@ ...@@ -98,9 +97,10 @@
'testing', 'testing',
'xhr_custom_status', 'xhr_custom_status',
'xhr_user_search' 'xhr_user_search'
]; ]));
_.extend(this, _.pick(settings, whitelist));
// Translation machinery
// ---------------------
var __ = $.proxy(function (str) { var __ = $.proxy(function (str) {
// Translation factory // Translation factory
if (this.i18n === undefined) { if (this.i18n === undefined) {
...@@ -124,6 +124,9 @@ ...@@ -124,6 +124,9 @@
*/ */
return str; return str;
}; };
// Translation aware constants
// ---------------------------
var OTR_CLASS_MAPPING = {}; var OTR_CLASS_MAPPING = {};
OTR_CLASS_MAPPING[UNENCRYPTED] = 'unencrypted'; OTR_CLASS_MAPPING[UNENCRYPTED] = 'unencrypted';
OTR_CLASS_MAPPING[UNVERIFIED] = 'unverified'; OTR_CLASS_MAPPING[UNVERIFIED] = 'unverified';
...@@ -136,7 +139,22 @@ ...@@ -136,7 +139,22 @@
OTR_TRANSLATED_MAPPING[VERIFIED] = __('verified'); OTR_TRANSLATED_MAPPING[VERIFIED] = __('verified');
OTR_TRANSLATED_MAPPING[FINISHED] = __('finished'); OTR_TRANSLATED_MAPPING[FINISHED] = __('finished');
var STATUSES = {
'dnd': __('This contact is busy'),
'online': __('This contact is online'),
'offline': __('This contact is offline'),
'unavailable': __('This contact is unavailable'),
'xa': __('This contact is away for an extended period'),
'away': __('This contact is away')
};
// Module-level variables
// ----------------------
this.callback = callback || function () {};
this.msg_counter = 0; this.msg_counter = 0;
// Module-level functions
// ----------------------
this.autoLink = function (text) { this.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;
...@@ -161,6 +179,46 @@ ...@@ -161,6 +179,46 @@
} }
}; };
this.getVCard = function (jid, callback, errback) {
converse.connection.vcard.get(
$.proxy(function (iq) {
// Successful callback
$vcard = $(iq).find('vCard');
var fullname = $vcard.find('FN').text(),
img = $vcard.find('BINVAL').text(),
img_type = $vcard.find('TYPE').text(),
url = $vcard.find('URL').text();
if (jid) {
var rosteritem = converse.roster.get(jid);
if (rosteritem) {
rosteritem.save({
'fullname': fullname || jid,
'image_type': img_type,
'image': img,
'url': url,
'vcard_updated': converse.toISOString(new Date())
});
}
}
if (callback) {
callback(jid, fullname, img, img_type, url);
}
}, this),
jid,
function (iq) {
// Error callback
var rosteritem = converse.roster.get(jid);
if (rosteritem) {
rosteritem.save({
'vcard_updated': converse.toISOString(new Date())
});
}
if (errback) {
errback(iq);
}
});
};
this.onConnect = function (status) { this.onConnect = function (status) {
if (status === Strophe.Status.CONNECTED) { if (status === Strophe.Status.CONNECTED) {
converse.log('Connected'); converse.log('Connected');
...@@ -257,51 +315,101 @@ ...@@ -257,51 +315,101 @@
this.updateMsgCounter(); this.updateMsgCounter();
}; };
this.collections = { this.showControlBox = function () {
/* FIXME: XEP-0136 specifies 'urn:xmpp:archive' but the mod_archive_odbc var controlbox = this.chatboxes.get('controlbox');
* add-on for ejabberd wants the URL below. This might break for other if (!controlbox) {
* Jabber servers. this.chatboxes.add({
*/ id: 'controlbox',
'URI': 'http://www.xmpp.org/extensions/xep-0136.html#ns' box_id: 'controlbox',
visible: true
});
if (this.connection) {
this.chatboxes.get('controlbox').save();
}
} else {
controlbox.trigger('show');
}
}; };
this.collections.getLastCollection = function (jid, callback) { this.toggleControlBox = function () {
var bare_jid = Strophe.getBareJidFromJid(jid), if ($("div#controlbox").is(':visible')) {
iq = $iq({'type':'get'}) var controlbox = this.chatboxes.get('controlbox');
.c('list', {'xmlns': this.URI, if (this.connection) {
'with': bare_jid controlbox.destroy();
}) } else {
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'}) controlbox.trigger('hide');
.c('before').up() }
.c('max') } else {
.t('1'); this.showControlBox();
}
};
converse.connection.sendIQ(iq, this.initStatus = function (callback) {
callback, this.xmppstatus = new this.XMPPStatus();
function () { var id = hex_sha1('converse.xmppstatus-'+this.bare_jid);
converse.log('Error while retrieving collections'); this.xmppstatus.id = id; // This appears to be necessary for backbone.localStorage
}); this.xmppstatus.localStorage = new Backbone.LocalStorage(id);
this.xmppstatus.fetch({success: callback, error: callback});
}; };
this.collections.getLastMessages = function (jid, callback) { this.initRoster = function () {
var that = this; // Set up the roster
this.getLastCollection(jid, function (result) { this.roster = new this.RosterItems();
// Retrieve the last page of a collection (max 30 elements). this.roster.localStorage = new Backbone.LocalStorage(
var $collection = $(result).find('chat'), hex_sha1('converse.rosteritems-'+converse.bare_jid));
jid = $collection.attr('with'),
start = $collection.attr('start'), // Register callbacks that depend on the roster
iq = $iq({'type':'get'}) this.connection.roster.registerCallback(
.c('retrieve', {'start': start, $.proxy(this.roster.rosterHandler, this.roster),
'xmlns': that.URI, null, 'presence', null);
'with': jid
}) this.connection.addHandler(
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'}) $.proxy(this.roster.subscribeToSuggestedItems, this.roster),
.c('max') 'http://jabber.org/protocol/rosterx', 'message', null);
.t('30');
converse.connection.sendIQ(iq, callback); this.connection.addHandler(
}); $.proxy(function (presence) {
this.presenceHandler(presence);
return true;
}, this.roster), null, 'presence', null);
// No create the view which will fetch roster items from
// localStorage
this.rosterview = new this.RosterView({'model':this.roster});
}; };
this.onConnected = function () {
if (this.debug) {
this.connection.xmlInput = function (body) { console.log(body); };
this.connection.xmlOutput = function (body) { console.log(body); };
Strophe.log = function (level, msg) { console.log(level+' '+msg); };
Strophe.error = function (msg) { console.log('ERROR: '+msg); };
}
this.bare_jid = Strophe.getBareJidFromJid(this.connection.jid);
this.domain = Strophe.getDomainFromJid(this.connection.jid);
this.features = new this.Features();
this.initStatus($.proxy(function () {
this.initRoster();
this.chatboxes.onConnected();
this.connection.roster.get(function () {});
$(window).on("blur focus", $.proxy(function(e) {
if ((this.windowState != e.type) && (e.type == 'focus')) {
converse.clearMsgCounter();
}
this.windowState = e.type;
},this));
this.giveFeedback(__('Online Contacts'));
if (this.testing) {
this.callback(this);
} else {
this.callback();
}
}, this));
};
// Backbone Models and Views
// -------------------------
this.Message = Backbone.Model.extend(); this.Message = Backbone.Model.extend();
this.Messages = Backbone.Collection.extend({ this.Messages = Backbone.Collection.extend({
...@@ -2275,19 +2383,11 @@ ...@@ -2275,19 +2383,11 @@
ask = item.get('ask'), ask = item.get('ask'),
subscription = item.get('subscription'); subscription = item.get('subscription');
var statuses = {
'dnd': __('This contact is busy'),
'online': __('This contact is online'),
'offline': __('This contact is offline'),
'unavailable': __('This contact is unavailable'),
'xa': __('This contact is away for an extended period'),
'away': __('This contact is away')
};
var classes_to_remove = [ var classes_to_remove = [
'current-xmpp-contact', 'current-xmpp-contact',
'pending-xmpp-contact', 'pending-xmpp-contact',
'requesting-xmpp-contact' 'requesting-xmpp-contact'
].concat(_.keys(statuses)); ].concat(_.keys(STATUSES));
_.each(classes_to_remove, _.each(classes_to_remove,
function (cls) { function (cls) {
...@@ -2298,63 +2398,23 @@ ...@@ -2298,63 +2398,23 @@
this.$el.addClass(item.get('chat_status')); this.$el.addClass(item.get('chat_status'));
if ((ask === 'subscribe') && (converse.allow_contact_requests)) { if (ask === 'subscribe') {
this.$el.addClass('pending-xmpp-contact'); this.$el.addClass('pending-xmpp-contact');
this.$el.html(this.pending_template(item.toJSON())); this.$el.html(this.pending_template(item.toJSON()));
} else if ((ask === 'request') && (converse.allow_contact_requests)) { } 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()));
converse.showControlBox(); converse.showControlBox();
} else if (subscription === 'both' || ((subscription === 'to') && converse.allow_contact_requests)) { } else if (subscription === 'both' || subscription === 'to') {
this.$el.addClass('current-xmpp-contact'); this.$el.addClass('current-xmpp-contact');
this.$el.html(this.template( this.$el.html(this.template(
_.extend(item.toJSON(), {'status_desc': statuses[item.get('chat_status')||'offline']}) _.extend(item.toJSON(), {'status_desc': STATUSES[item.get('chat_status')||'offline']})
)); ));
} }
return this; return this;
} }
}); });
this.getVCard = function (jid, callback, errback) {
converse.connection.vcard.get(
$.proxy(function (iq) {
// Successful callback
$vcard = $(iq).find('vCard');
var fullname = $vcard.find('FN').text(),
img = $vcard.find('BINVAL').text(),
img_type = $vcard.find('TYPE').text(),
url = $vcard.find('URL').text();
if (jid) {
var rosteritem = converse.roster.get(jid);
if (rosteritem) {
rosteritem.save({
'fullname': fullname || jid,
'image_type': img_type,
'image': img,
'url': url,
'vcard_updated': converse.toISOString(new Date())
});
}
}
if (callback) {
callback(jid, fullname, img, img_type, url);
}
}, this),
jid,
function (iq) {
// Error callback
var rosteritem = converse.roster.get(jid);
if (rosteritem) {
rosteritem.save({
'vcard_updated': converse.toISOString(new Date())
});
}
if (errback) {
errback(iq);
}
});
};
this.RosterItems = Backbone.Collection.extend({ this.RosterItems = Backbone.Collection.extend({
model: converse.RosterItem, model: converse.RosterItem,
comparator : function (rosteritem) { comparator : function (rosteritem) {
...@@ -2710,6 +2770,14 @@ ...@@ -2710,6 +2770,14 @@
chatbox.save(changes); chatbox.save(changes);
}, },
renderRosterItem: function () {
if ($.contains(document.documentElement, view.el)) {
view.render();
} else {
$my_contacts.after(view.render().el);
}
},
render: function (item) { render: function (item) {
var $my_contacts = this.$el.find('#xmpp-contacts'), var $my_contacts = this.$el.find('#xmpp-contacts'),
$contact_requests = this.$el.find('#xmpp-contact-requests'), $contact_requests = this.$el.find('#xmpp-contact-requests'),
...@@ -2730,11 +2798,7 @@ ...@@ -2730,11 +2798,7 @@
$contact_requests.after(view.render().el); $contact_requests.after(view.render().el);
$contact_requests.after($contact_requests.siblings('dd.requesting-xmpp-contact').tsort(crit)); $contact_requests.after($contact_requests.siblings('dd.requesting-xmpp-contact').tsort(crit));
} else if (subscription === 'both' || subscription === 'to') { } else if (subscription === 'both' || subscription === 'to') {
if ($.contains(document.documentElement, view.el)) { this.renderRosterItem();
view.render();
} else {
$my_contacts.after(view.render().el);
}
} }
changed_presence = view.model.changed.chat_status; changed_presence = view.model.changed.chat_status;
if (changed_presence) { if (changed_presence) {
...@@ -3057,7 +3121,7 @@ ...@@ -3057,7 +3121,7 @@
showConnectButton: function () { showConnectButton: function () {
var $form = this.$el.find('#converse-login'); var $form = this.$el.find('#converse-login');
var $button = $form.find('input[type=submit]') var $button = $form.find('input[type=submit]');
if ($button.length) { if ($button.length) {
$button.show().siblings('span').remove(); $button.show().siblings('span').remove();
} }
...@@ -3112,98 +3176,8 @@ ...@@ -3112,98 +3176,8 @@
} }
}); });
this.showControlBox = function () { // Initialization
var controlbox = this.chatboxes.get('controlbox'); // --------------
if (!controlbox) {
this.chatboxes.add({
id: 'controlbox',
box_id: 'controlbox',
visible: true
});
if (this.connection) {
this.chatboxes.get('controlbox').save();
}
} else {
controlbox.trigger('show');
}
};
this.toggleControlBox = function () {
if ($("div#controlbox").is(':visible')) {
var controlbox = this.chatboxes.get('controlbox');
if (this.connection) {
controlbox.destroy();
} else {
controlbox.trigger('hide');
}
} else {
this.showControlBox();
}
};
this.initStatus = function (callback) {
this.xmppstatus = new this.XMPPStatus();
var id = hex_sha1('converse.xmppstatus-'+this.bare_jid);
this.xmppstatus.id = id; // This appears to be necessary for backbone.localStorage
this.xmppstatus.localStorage = new Backbone.LocalStorage(id);
this.xmppstatus.fetch({success: callback, error: callback});
};
this.initRoster = function () {
// Set up the roster
this.roster = new this.RosterItems();
this.roster.localStorage = new Backbone.LocalStorage(
hex_sha1('converse.rosteritems-'+converse.bare_jid));
// Register callbacks that depend on the roster
this.connection.roster.registerCallback(
$.proxy(this.roster.rosterHandler, this.roster),
null, 'presence', null);
this.connection.addHandler(
$.proxy(this.roster.subscribeToSuggestedItems, this.roster),
'http://jabber.org/protocol/rosterx', 'message', null);
this.connection.addHandler(
$.proxy(function (presence) {
this.presenceHandler(presence);
return true;
}, this.roster), null, 'presence', null);
// No create the view which will fetch roster items from
// localStorage
this.rosterview = new this.RosterView({'model':this.roster});
};
this.onConnected = function () {
if (this.debug) {
this.connection.xmlInput = function (body) { console.log(body); };
this.connection.xmlOutput = function (body) { console.log(body); };
Strophe.log = function (level, msg) { console.log(level+' '+msg); };
Strophe.error = function (msg) { console.log('ERROR: '+msg); };
}
this.bare_jid = Strophe.getBareJidFromJid(this.connection.jid);
this.domain = Strophe.getDomainFromJid(this.connection.jid);
this.features = new this.Features();
this.initStatus($.proxy(function () {
this.initRoster();
this.chatboxes.onConnected();
this.connection.roster.get(function () {});
$(window).on("blur focus", $.proxy(function(e) {
if ((this.windowState != e.type) && (e.type == 'focus')) {
converse.clearMsgCounter();
}
this.windowState = e.type;
},this));
this.giveFeedback(__('Online Contacts'));
if (this.testing) {
this.callback(this);
} else {
this.callback();
}
}, this));
};
// This is the end of the initialize method. // This is the end of the initialize method.
this.chatboxes = new this.ChatBoxes(); this.chatboxes = new this.ChatBoxes();
......
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