Merge branch '0.6.x'

Conflicts:
	converse.js
This commit is contained in:
JC Brand 2013-10-05 22:38:14 +02:00
commit b111e60c1d

View File

@ -46,6 +46,7 @@
var converse = this;
// Constants
// ---------
var UNENCRYPTED = 0;
var UNVERIFIED= 1;
var VERIFIED= 2;
@ -54,7 +55,8 @@
ENTER: 13
};
// Default values
// Default configuration values
// ----------------------------
this.allow_contact_requests = true;
this.allow_muc = true;
this.allow_otr = true;
@ -72,11 +74,8 @@
this.xhr_custom_status = false;
this.xhr_user_search = false;
this.callback = callback || function () {};
// Allow only the whitelisted settings attributes to be overwritten,
// nothing else.
whitelist = [
// Allow only whitelisted configuration attributes to be overwritten
_.extend(this, _.pick(settings, [
'allow_contact_requests',
'allow_muc',
'allow_otr',
@ -98,9 +97,10 @@
'testing',
'xhr_custom_status',
'xhr_user_search'
];
_.extend(this, _.pick(settings, whitelist));
]));
// Translation machinery
// ---------------------
var __ = $.proxy(function (str) {
// Translation factory
if (this.i18n === undefined) {
@ -124,6 +124,9 @@
*/
return str;
};
// Translation aware constants
// ---------------------------
var OTR_CLASS_MAPPING = {};
OTR_CLASS_MAPPING[UNENCRYPTED] = 'unencrypted';
OTR_CLASS_MAPPING[UNVERIFIED] = 'unverified';
@ -136,7 +139,22 @@
OTR_TRANSLATED_MAPPING[VERIFIED] = __('verified');
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;
// Module-level functions
// ----------------------
this.autoLink = function (text) {
// Convert URLs into hyperlinks
var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
@ -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) {
if (status === Strophe.Status.CONNECTED) {
converse.log('Connected');
@ -257,51 +315,101 @@
this.updateMsgCounter();
};
this.collections = {
/* 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
* Jabber servers.
*/
'URI': 'http://www.xmpp.org/extensions/xep-0136.html#ns'
};
this.collections.getLastCollection = function (jid, callback) {
var bare_jid = Strophe.getBareJidFromJid(jid),
iq = $iq({'type':'get'})
.c('list', {'xmlns': this.URI,
'with': bare_jid
})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('before').up()
.c('max')
.t('1');
converse.connection.sendIQ(iq,
callback,
function () {
converse.log('Error while retrieving collections');
this.showControlBox = function () {
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.collections.getLastMessages = function (jid, callback) {
var that = this;
this.getLastCollection(jid, function (result) {
// Retrieve the last page of a collection (max 30 elements).
var $collection = $(result).find('chat'),
jid = $collection.attr('with'),
start = $collection.attr('start'),
iq = $iq({'type':'get'})
.c('retrieve', {'start': start,
'xmlns': that.URI,
'with': jid
})
.c('set', {'xmlns': 'http://jabber.org/protocol/rsm'})
.c('max')
.t('30');
converse.connection.sendIQ(iq, callback);
});
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));
};
// Backbone Models and Views
// -------------------------
this.Message = Backbone.Model.extend();
this.Messages = Backbone.Collection.extend({
@ -2275,19 +2383,11 @@
ask = item.get('ask'),
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 = [
'current-xmpp-contact',
'pending-xmpp-contact',
'requesting-xmpp-contact'
].concat(_.keys(statuses));
].concat(_.keys(STATUSES));
_.each(classes_to_remove,
function (cls) {
@ -2298,63 +2398,23 @@
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.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.html(this.request_template(item.toJSON()));
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.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;
}
});
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({
model: converse.RosterItem,
comparator : function (rosteritem) {
@ -2710,6 +2770,14 @@
chatbox.save(changes);
},
renderRosterItem: function () {
if ($.contains(document.documentElement, view.el)) {
view.render();
} else {
$my_contacts.after(view.render().el);
}
},
render: function (item) {
var $my_contacts = this.$el.find('#xmpp-contacts'),
$contact_requests = this.$el.find('#xmpp-contact-requests'),
@ -2730,11 +2798,7 @@
$contact_requests.after(view.render().el);
$contact_requests.after($contact_requests.siblings('dd.requesting-xmpp-contact').tsort(crit));
} else if (subscription === 'both' || subscription === 'to') {
if ($.contains(document.documentElement, view.el)) {
view.render();
} else {
$my_contacts.after(view.render().el);
}
this.renderRosterItem();
}
changed_presence = view.model.changed.chat_status;
if (changed_presence) {
@ -3057,7 +3121,7 @@
showConnectButton: function () {
var $form = this.$el.find('#converse-login');
var $button = $form.find('input[type=submit]')
var $button = $form.find('input[type=submit]');
if ($button.length) {
$button.show().siblings('span').remove();
}
@ -3112,98 +3176,8 @@
}
});
this.showControlBox = function () {
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));
};
// Initialization
// --------------
// This is the end of the initialize method.
this.chatboxes = new this.ChatBoxes();