var helpers = (function (helpers) { helpers.hash = function (str) { // FIXME if (str == 'online-users-container') { return str; } var shaobj = new jsSHA(str); return shaobj.getHash("HEX"); }; return helpers; })(helpers || {}); var xmppchat = (function (jarnxmpp, $, console) { var ob = jarnxmpp; /* 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. */ ob.Collections = { 'URI': 'http://www.xmpp.org/extensions/xep-0136.html#ns' }; ob.Messages = jarnxmpp.Messages || {}; ob.Presence = jarnxmpp.Presence || {}; ob.Messages.ClientStorage = (function () { methods = {}; methods.addMessage = function (jid, msg, direction) { var bare_jid = Strophe.getBareJidFromJid(jid), now = new Date().toISOString(), msgs = store.get(bare_jid) || []; if (msgs.length >= 30) { msgs.shift(); } msgs.push(now+' '+direction+' '+msg); store.set(bare_jid, msgs); }; methods.getMessages = function (jid) { return store.get(jid) || []; }; return methods; })(); ob.Messages.getMessages = function (jid, callback) { var bare_jid = Strophe.getBareJidFromJid(jid), msgs = this.ClientStorage.getMessages(bare_jid); callback(msgs); }; ob.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'); xmppchat.connection.sendIQ(iq, callback, function () { console.log('Error while retrieving collections'); }); }; ob.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'); xmppchat.connection.sendIQ(iq, callback); }); }; ob.Presence.getOwnStatus = function () { return xmppchat.Storage.get(xmppchat.username+'-xmpp-status'); }; ob.Presence.onlineCount = function () { return xmppchat.ChatPartners.getTotal(); }; ob.Taskbuffer = (function ($) { // Executes tasks one after another (i.e next task is started only when // the previous one has been completed). buffer = {}; // Tasks must be objects with keys: 'that', 'method' and 'parameters' // 'that' the context for the method, while 'parameters' is the list of arguments // passed to it. buffer.tasks = []; buffer.deferred = $.when(); buffer.handleTasks = function () { var task; // If the current deferred task is resolved and there are more tasks if (buffer.deferred.isResolved() && buffer.tasks.length > 0) { // Get the next task in the queue and set the new deferred. task = buffer.tasks.shift(); buffer.deferred = $.when(task.method.apply(task.that, task.parameters)); if (buffer.tasks.length > 0) { buffer.deferred.done(buffer.handleTasks); } } }; return buffer; })(jQuery); return ob; })(jarnxmpp || {}, jQuery, console || {log: function(){}}); xmppchat.ChatBox = Backbone.Model.extend({ hash: function (str) { var shaobj = new jsSHA(str); return shaobj.getHash("HEX"); }, initialize: function () { this.set({ 'user_id' : Strophe.getNodeFromJid(this.get('jid')), 'chat_id' : this.hash(this.get('jid')) }); } }); xmppchat.ChatBoxView = Backbone.View.extend({ tagName: 'div', className: 'chatbox', events: { 'click .close-chatbox-button': 'closeChat', 'keypress textarea.chat-textarea': 'keyPressed' }, 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( '
' + ''+time+' me:  ' + ''+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'), div = $('
'), $chat_content = $(this.el).find('.chat-content'), user_id = Strophe.getNodeFromJid(jid); if (!body) { if (composing.length > 0) { message_html = div.addClass('chat-event').text(user_id+ ' is typing...'); $chat_content.find('div.chat-event').remove().end().append(message_html); } } else { // TODO: ClientStorage xmppchat.Messages.ClientStorage.addMessage(jid, body, 'from'); if (xmppchat.xmppstatus.getOwnStatus() === 'offline') { return; } // only update the UI if the user is not offline var time = (new Date()).toLocaleTimeString().substring(0,5), text = body.replace(/
/g, ""); div.addClass('chat-message'); if (($(message).find('delay').length > 0)) { div.addClass('delayed'); } $chat_content.find('div.chat-event').remove(); message_html = div.append( ''+time+' '+user_id+':  ' + ''+text+'' ); $chat_content.append(message_html); // FIXME: // xmppchat.UI.msg_counter += 1; // xmppchat.UI.updateMsgCounter(); } $chat_content.scrollTop($chat_content[0].scrollHeight); }, sendMessage: function (text) { // 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. // FIXME: see if @@content-transform is required 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('chat_id')).hide('fast', function () { that.removeChatFromCookie(that.model.get('id')); // Only reorder chats if it wasn't the last chat being closed. var offset = parseInt($(that.el).css('right'), 10) + xmppchat.chatboxesview.chatbox_width; if ($("div[style*='right: "+offset+"px']").length > 0) { xmppchat.chatboxesview.reorderChats(); } }); }, initialize: function (){ $('body').append($(this.el).hide()); }, template: _.template('
' + '
<%= user_id %>
' + 'X' + '
' + '
' + '
' + '
' + '