Commit 1c125da767ba502b800bd58896ed1aaac828a092
Committed by
Joenio Costa
1 parent
c9fb1096
Exists in
master
and in
22 other branches
chat fixes and new features
* try to reconnect if connection fails * fix ordering * reconnect if connection is lost but user status is not offline * remove some anchors * keep track of buddies order on the client * tweak notification to work on chromium * respect async request order * focus on window when notification clicked * deal with window visibility * add chat-buttons * fix recent_conversations * fix sorting and join room on opening * remove obsolete code * adjusting indentation (sorry but I needed too...) * fix load_conversation * return identifier as key on avatars action * fix typo * add timeout to notification * deal properly with offline messages * fix notification sound * clear unread after loading conversation on background * ignore message from room * add unread messages counter on chat-label * as for notification permission as soon as the chat connects * add profile_info_action to open chat * using jid to save message instead of identifier * add profile_info_action to open chat * as for notification permission as soon as the chat connects * add unread messages counter on chat-label Squashed and Signed-off-by: Joenio Costa <joenio@colivre.coop.br>
Showing
21 changed files
with
1050 additions
and
817 deletions
Show diff stats
app/controllers/public/chat_controller.rb
| ... | ... | @@ -2,6 +2,7 @@ class ChatController < PublicController |
| 2 | 2 | |
| 3 | 3 | before_filter :login_required |
| 4 | 4 | before_filter :check_environment_feature |
| 5 | + before_filter :can_send_message, :only => :register_message | |
| 5 | 6 | |
| 6 | 7 | def start_session |
| 7 | 8 | login = user.jid |
| ... | ... | @@ -54,6 +55,16 @@ class ChatController < PublicController |
| 54 | 55 | end |
| 55 | 56 | end |
| 56 | 57 | |
| 58 | + def avatars | |
| 59 | + profiles = environment.profiles.where(:identifier => params[:profiles]) | |
| 60 | + avatar_map = profiles.inject({}) do |result, profile| | |
| 61 | + result[profile.identifier] = profile_icon(profile, :minor) | |
| 62 | + result | |
| 63 | + end | |
| 64 | + | |
| 65 | + render_json avatar_map | |
| 66 | + end | |
| 67 | + | |
| 57 | 68 | def update_presence_status |
| 58 | 69 | if request.xhr? |
| 59 | 70 | current_user.update_attributes({:chat_status_at => DateTime.now}.merge(params[:status] || {})) |
| ... | ... | @@ -62,11 +73,17 @@ class ChatController < PublicController |
| 62 | 73 | end |
| 63 | 74 | |
| 64 | 75 | def save_message |
| 65 | - to = environment.profiles.find_by_identifier(params[:to]) | |
| 66 | - body = params[:body] | |
| 67 | - | |
| 68 | - ChatMessage.create!(:to => to, :from => user, :body => body) | |
| 69 | - render :text => 'ok' | |
| 76 | + if request.post? | |
| 77 | + to = environment.profiles.where(:identifier => params[:to]).first | |
| 78 | + body = params[:body] | |
| 79 | + | |
| 80 | + begin | |
| 81 | + ChatMessage.create!(:to => to, :from => user, :body => body) | |
| 82 | + return render_json({:status => 0}) | |
| 83 | + rescue Exception => exception | |
| 84 | + return render_json({:status => 3, :message => exception.to_s, :backtrace => exception.backtrace}) | |
| 85 | + end | |
| 86 | + end | |
| 70 | 87 | end |
| 71 | 88 | |
| 72 | 89 | def recent_messages |
| ... | ... | @@ -90,8 +107,9 @@ class ChatController < PublicController |
| 90 | 107 | end |
| 91 | 108 | |
| 92 | 109 | def recent_conversations |
| 93 | - conversations_order = ActiveRecord::Base.connection.execute("select profiles.identifier from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc").entries.map {|e| e['identifier']} | |
| 94 | - render :json => {:order => conversations_order.reverse, :domain => environment.default_hostname.gsub('.','-')}.to_json | |
| 110 | + profiles = Profile.find_by_sql("select profiles.* from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc") | |
| 111 | + jids = profiles.map(&:jid).reverse | |
| 112 | + render :json => jids.to_json | |
| 95 | 113 | end |
| 96 | 114 | |
| 97 | 115 | #TODO Ideally this is done through roster table on ejabberd. |
| ... | ... | @@ -108,4 +126,14 @@ class ChatController < PublicController |
| 108 | 126 | end |
| 109 | 127 | end |
| 110 | 128 | |
| 129 | + def can_send_message | |
| 130 | + return render_json({:status => 1, :message => 'Missing parameters!'}) if params[:from].nil? || params[:to].nil? || params[:message].nil? | |
| 131 | + return render_json({:status => 2, :message => 'You can not send message as another user!'}) if params[:from] != user.jid | |
| 132 | + # TODO Maybe register the jid in a table someday to avoid this below | |
| 133 | + return render_json({:status => 3, :messsage => 'You can not send messages to strangers!'}) if user.friends.where(:identifier => params[:to].split('@').first).blank? | |
| 134 | + end | |
| 135 | + | |
| 136 | + def render_json(result) | |
| 137 | + render :text => result.to_json | |
| 138 | + end | |
| 111 | 139 | end | ... | ... |
app/helpers/chat_helper.rb
| ... | ... | @@ -9,12 +9,12 @@ module ChatHelper |
| 9 | 9 | avatar = profile_image(user, :portrait, :class => 'avatar') |
| 10 | 10 | content_tag('span', |
| 11 | 11 | link_to(avatar + content_tag('span', user.name) + ui_icon('ui-icon-triangle-1-s'), |
| 12 | - '#', | |
| 12 | + '', | |
| 13 | 13 | :onclick => 'toggleMenu(this); return false', |
| 14 | 14 | :class => icon_class + ' simplemenu-trigger' |
| 15 | 15 | ) + |
| 16 | 16 | content_tag('ul', |
| 17 | - links.map{|link| content_tag('li', link_to(link[1], '#', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"), | |
| 17 | + links.map{|link| content_tag('li', link_to(link[1], '', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"), | |
| 18 | 18 | :style => 'display: none; z-index: 100', |
| 19 | 19 | :class => 'simplemenu-submenu' |
| 20 | 20 | ), | ... | ... |
app/models/chat_message.rb
app/views/blocks/profile_info_actions/_community.html.erb
app/views/blocks/profile_info_actions/_enterprise.html.erb
| ... | ... | @@ -8,5 +8,5 @@ |
| 8 | 8 | <li><%= button(:'menu-mail', _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button'} ) %></li> |
| 9 | 9 | <% end %> |
| 10 | 10 | |
| 11 | - <li><%= report_abuse(profile, :button) %></li> | |
| 11 | + <%= render :partial => 'blocks/profile_info_actions/common' %> | |
| 12 | 12 | </ul> | ... | ... |
app/views/blocks/profile_info_actions/_person.html.erb
| ... | ... | @@ -11,6 +11,6 @@ |
| 11 | 11 | <li><%= button(:back, _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}) %></li> |
| 12 | 12 | <% end %> |
| 13 | 13 | |
| 14 | - <li><%= report_abuse(profile, :button) %></li> | |
| 14 | + <%= render :partial => 'blocks/profile_info_actions/common' %> | |
| 15 | 15 | <% end %> |
| 16 | 16 | </ul> | ... | ... |
app/views/chat/start_session_error.html.erb
| 1 | 1 | <p> |
| 2 | 2 | <%= ui_icon('ui-icon-alert') %> |
| 3 | -<%= _('Could not connect to chat') %>, <a id='chat-retry' href='#' data-jid='<%= user.jid %>'><%= _('try again') %></a>. | |
| 3 | +<%= _('Could not connect to chat') %>, <a id='chat-retry' href='' data-jid='<%= user.jid %>'><%= _('try again') %></a>. | |
| 4 | 4 | </p> | ... | ... |
app/views/shared/logged_in/xmpp_chat.html.erb
| ... | ... | @@ -7,13 +7,13 @@ |
| 7 | 7 | var $own_name = '<%= user.name %>'; |
| 8 | 8 | var $muc_domain = '<%= "conference.#{environment.default_hostname}" %>'; |
| 9 | 9 | var $bosh_service = '//<%= environment.default_hostname %>/http-bind'; |
| 10 | - var $user_unavailable_error = '<%= _("<strong>ooops!</strong> The message could not be sent because the user is not online") %>'; | |
| 10 | + var $user_unavailable_error = '<%= _("The user is not online now. He/She will receive these messages as soon as he/she gets online.") %>'; | |
| 11 | 11 | var $update_presence_status_every = <%= User.expires_chat_status_every.minutes %>; |
| 12 | 12 | var $presence = '<%= current_user.last_chat_status %>'; |
| 13 | 13 | </script> |
| 14 | 14 | |
| 15 | - | |
| 16 | 15 | <div id="chat-label"> |
| 16 | + <span id="unread-messages"></span> | |
| 17 | 17 | <span class="right-arrow">▶</span> |
| 18 | 18 | <span class="title"><%= _('Chat') %></span> |
| 19 | 19 | </div> |
| ... | ... | @@ -98,10 +98,5 @@ |
| 98 | 98 | </div> |
| 99 | 99 | </div> |
| 100 | 100 | </div> |
| 101 | - | |
| 102 | - <div class="error-message"> | |
| 103 | - <span class='error'>%{text}</span> | |
| 104 | - </div> | |
| 105 | - | |
| 106 | 101 | </div> |
| 107 | 102 | </div> | ... | ... |
| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | +<% label_name = profile.person? ? _('Open chat') : _('Join chat room') %> | |
| 2 | +<% display = profile.person? ? profile.friends.include?(user) : profile.members.include?(user) %> | |
| 3 | + | |
| 4 | +<% if display %> | |
| 5 | + <li> | |
| 6 | + <%= button(:chat, label_name , {}, :class => 'open-conversation', 'data-jid' => profile.jid) %> | |
| 7 | + </li> | |
| 8 | +<% end %> | ... | ... |
db/migrate/20140820173129_create_chat_messages.rb
| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | +class CreateChatMessages < ActiveRecord::Migration | |
| 2 | + def up | |
| 3 | + create_table :chat_messages do |t| | |
| 4 | + t.references :from | |
| 5 | + t.references :to | |
| 6 | + t.text :body | |
| 7 | + t.timestamps | |
| 8 | + end | |
| 9 | + add_index :chat_messages, :from_id | |
| 10 | + add_index :chat_messages, :to_id | |
| 11 | + add_index :chat_messages, :created_at | |
| 12 | + end | |
| 13 | + | |
| 14 | + def down | |
| 15 | + drop_table :chat_messages | |
| 16 | + remove_index :chat_messages, :from | |
| 17 | + remove_index :chat_messages, :to | |
| 18 | + remove_index :chat_messages, :created_at | |
| 19 | + end | |
| 20 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -245,13 +245,17 @@ ActiveRecord::Schema.define(:version => 20150513213939) do |
| 245 | 245 | end |
| 246 | 246 | |
| 247 | 247 | create_table "chat_messages", :force => true do |t| |
| 248 | - t.integer "to_id" | |
| 249 | 248 | t.integer "from_id" |
| 250 | - t.string "body" | |
| 249 | + t.integer "to_id" | |
| 250 | + t.text "body" | |
| 251 | 251 | t.datetime "created_at", :null => false |
| 252 | 252 | t.datetime "updated_at", :null => false |
| 253 | 253 | end |
| 254 | 254 | |
| 255 | + add_index "chat_messages", ["created_at"], :name => "index_chat_messages_on_created_at" | |
| 256 | + add_index "chat_messages", ["from_id"], :name => "index_chat_messages_on_from_id" | |
| 257 | + add_index "chat_messages", ["to_id"], :name => "index_chat_messages_on_to_id" | |
| 258 | + | |
| 255 | 259 | create_table "comments", :force => true do |t| |
| 256 | 260 | t.string "title" |
| 257 | 261 | t.text "body" | ... | ... |
debian/noosfero.install
debian/update-noosfero-apache
| ... | ... | @@ -18,9 +18,20 @@ if test -x /usr/share/noosfero/script/apacheconf; then |
| 18 | 18 | fi |
| 19 | 19 | |
| 20 | 20 | apache_site='/etc/apache2/sites-available/noosfero' |
| 21 | + apache_site_configs='/etc/noosfero/apache.d' | |
| 21 | 22 | if ! test -e "$apache_site"; then |
| 22 | 23 | echo "Generating apache virtual host ..." |
| 23 | 24 | cd /usr/share/noosfero && su noosfero -c "RAILS_ENV=production ./script/apacheconf virtualhosts" > "$apache_site" |
| 25 | + if ! test -d "$apache_site_configs"; then | |
| 26 | + echo "Creating noosfero site config folder ..." | |
| 27 | + mkdir $apache_site_configs | |
| 28 | + fi | |
| 29 | + else | |
| 30 | + pattern="Include \/etc\/noosfero\/apache\/virtualhost.conf" | |
| 31 | + include="Include \/etc\/noosfero\/apache.d\/*" | |
| 32 | + if ! cat $apache_site | grep "^ *$include" > /dev/null ; then | |
| 33 | + sed -i "s/.*$pattern.*/ $include\n&/" $apache_site | |
| 34 | + fi | |
| 24 | 35 | fi |
| 25 | 36 | |
| 26 | 37 | echo 'Noosfero Apache configuration updated.' | ... | ... |
public/javascripts/application.js
| ... | ... | @@ -1140,10 +1140,20 @@ function notifyMe(title, options) { |
| 1140 | 1140 | |
| 1141 | 1141 | // If the user is okay, let's create a notification |
| 1142 | 1142 | if (permission === "granted") { |
| 1143 | - notification = new Notification(title, options); | |
| 1143 | + notification = new Notification(title, options); | |
| 1144 | 1144 | } |
| 1145 | 1145 | }); |
| 1146 | 1146 | } |
| 1147 | + | |
| 1148 | + setTimeout(function() {notification.close()}, 5000); | |
| 1149 | + notification.onclick = function(){ | |
| 1150 | + notification.close(); | |
| 1151 | + // Chromium tweak | |
| 1152 | + window.open().close(); | |
| 1153 | + window.focus(); | |
| 1154 | + this.cancel(); | |
| 1155 | + }; | |
| 1156 | + | |
| 1147 | 1157 | return notification; |
| 1148 | 1158 | // At last, if the user already denied any notification, and you |
| 1149 | 1159 | // want to be respectful there is no need to bother them any more. | ... | ... |
public/javascripts/chat.js
| 1 | 1 | /* XMPP/Jabber Noosfero's client |
| 2 | 2 | |
| 3 | - XMPP Core: | |
| 4 | - http://xmpp.org/rfcs/rfc3920.html | |
| 3 | +XMPP Core: | |
| 4 | +http://xmpp.org/rfcs/rfc3920.html | |
| 5 | 5 | |
| 6 | - MUC support: | |
| 7 | - http://xmpp.org/extensions/xep-0045.html | |
| 6 | +MUC support: | |
| 7 | +http://xmpp.org/extensions/xep-0045.html | |
| 8 | 8 | |
| 9 | - Messages and presence: | |
| 10 | - http://xmpp.org/rfcs/rfc3921.html | |
| 9 | +Messages and presence: | |
| 10 | +http://xmpp.org/rfcs/rfc3921.html | |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | 13 | jQuery(function($) { |
| 14 | - // extending the current namespaces in Strophe.NS | |
| 15 | - Strophe.addNamespace('MUC_USER', 'http://jabber.org/protocol/muc#user'); | |
| 16 | - Strophe.addNamespace('MUC_OWNER', 'http://jabber.org/protocol/muc#owner'); | |
| 17 | - Strophe.addNamespace('CHAT_STATES', 'http://jabber.org/protocol/chatstates'); | |
| 18 | - Strophe.addNamespace('DATA_FORMS', 'jabber:x:data'); | |
| 19 | - | |
| 20 | - var Jabber = { | |
| 21 | - debug: true, | |
| 22 | - connection: null, | |
| 23 | - bosh_service: $bosh_service, | |
| 24 | - muc_domain: $muc_domain, | |
| 25 | - muc_supported: false, | |
| 26 | - presence_status: '', | |
| 27 | - conversation_prefix: 'conversation-', | |
| 28 | - jids: {}, | |
| 29 | - rooms: {}, | |
| 30 | - no_more_messages: {}, | |
| 31 | - | |
| 32 | - template: function(selector) { | |
| 33 | - return $('#chat #chat-templates '+selector).clone().html(); | |
| 34 | - }, | |
| 35 | - | |
| 36 | - jid_to_id: function (jid) { | |
| 37 | - return Strophe.getBareJidFromJid(jid).replace(/@/g, "-").replace(/\./g, "-"); | |
| 38 | - }, | |
| 39 | - | |
| 40 | - jid_of: function(jid_id) { | |
| 41 | - return Jabber.jids[jid_id].jid; | |
| 42 | - }, | |
| 43 | - name_of: function(jid_id) { | |
| 44 | - return Jabber.jids[jid_id].name; | |
| 45 | - }, | |
| 46 | - type_of: function(jid_id) { | |
| 47 | - return Jabber.jids[jid_id].type; | |
| 48 | - }, | |
| 49 | - unread_messages_of: function(jid_id, value) { | |
| 50 | - Jabber.jids[jid_id].unread_messages = (value == undefined ? Jabber.jids[jid_id].unread_messages : value); | |
| 51 | - return Jabber.jids[jid_id].unread_messages; | |
| 52 | - }, | |
| 53 | - | |
| 54 | - insert_or_update_user: function (list, item, jid, name, presence, template, type, remove_on_offline) { | |
| 55 | - var jid_id = Jabber.jid_to_id(jid); | |
| 56 | - var identifier = Strophe.getNodeFromJid(jid); | |
| 57 | - var html = template | |
| 58 | - .replace('%{jid_id}', jid_id) | |
| 59 | - .replace(/%{presence_status}/g, presence) | |
| 60 | - .replace('%{avatar}', getAvatar(identifier)) | |
| 61 | - .replace('%{name}', name); | |
| 62 | - | |
| 63 | - $(item).parent().remove(); | |
| 64 | - if(presence != 'offline' || !remove_on_offline) | |
| 65 | - $(list).append(html); | |
| 66 | - Jabber.jids[jid_id] = {jid: jid, name: name, type: type, presence: presence}; | |
| 67 | - }, | |
| 68 | - insert_or_update_group: function (jid, presence) { | |
| 69 | - var jid_id = Jabber.jid_to_id(jid); | |
| 70 | - var list = $('#buddy-list .buddies ul.'+presence); | |
| 71 | - var item = $('#' + jid_id); | |
| 72 | - presence = presence || ($(item).length > 0 ? $(item).parent('li').attr('class') : 'offline'); | |
| 73 | - log('adding or updating contact ' + jid + ' as ' + presence); | |
| 74 | - Jabber.insert_or_update_user(list, item, jid, Jabber.name_of(jid_id), presence, Jabber.template('.buddy-item'), 'groupchat'); | |
| 75 | - $("#chat-window .tab a[href='#"+ Jabber.conversation_prefix + jid_id +"']") | |
| 76 | - .removeClass() | |
| 77 | - .addClass('icon-menu-' + presence + '-11'); | |
| 78 | - }, | |
| 79 | - insert_or_update_contact: function (jid, name, presence) { | |
| 80 | - var jid_id = Jabber.jid_to_id(jid); | |
| 81 | - var item = $('#' + jid_id); | |
| 82 | - presence = presence || ($(item).length > 0 ? $(item).parent('li').attr('class') : 'offline'); | |
| 83 | - var list = $('#buddy-list .buddies ul' + (presence=='offline' ? '.offline' : '.online')); | |
| 84 | - | |
| 85 | - log('adding or updating contact ' + jid + ' as ' + presence); | |
| 86 | - Jabber.insert_or_update_user(list, item, jid, name, presence, Jabber.template('.buddy-item'), 'chat'); | |
| 87 | - $("#chat-window .tab a[href='#"+ Jabber.conversation_prefix + jid_id +"']") | |
| 88 | - .removeClass() | |
| 89 | - .addClass('icon-menu-' + presence + '-11'); | |
| 90 | - }, | |
| 91 | - insert_or_update_occupant: function (jid, name, presence, room_jid) { | |
| 92 | - log('adding or updating occupant ' + jid + ' as ' + presence); | |
| 93 | - var jid_id = Jabber.jid_to_id(jid); | |
| 94 | - var room_jid_id = Jabber.jid_to_id(room_jid); | |
| 95 | - var list = $('#' + Jabber.conversation_prefix + room_jid_id + ' .occupants ul'); | |
| 96 | - var item = $(list).find('a[data-id='+ jid_id +']'); | |
| 97 | - Jabber.insert_or_update_user(list, item, jid, name, presence, Jabber.template('.occupant-item'), 'chat', true); | |
| 98 | - if (Jabber.rooms[room_jid_id] === undefined) | |
| 99 | - Jabber.rooms[room_jid_id] = {}; | |
| 100 | - | |
| 101 | - var room = Jabber.rooms[room_jid_id]; | |
| 102 | - if(presence == 'offline') { | |
| 103 | - delete Jabber.rooms[room_jid_id][name]; | |
| 104 | - } | |
| 105 | - else { | |
| 106 | - Jabber.rooms[room_jid_id][name] = jid; | |
| 107 | - } | |
| 14 | + // extending the current namespaces in Strophe.NS | |
| 15 | + Strophe.addNamespace('MUC_USER', 'http://jabber.org/protocol/muc#user'); | |
| 16 | + Strophe.addNamespace('MUC_OWNER', 'http://jabber.org/protocol/muc#owner'); | |
| 17 | + Strophe.addNamespace('CHAT_STATES', 'http://jabber.org/protocol/chatstates'); | |
| 18 | + Strophe.addNamespace('DATA_FORMS', 'jabber:x:data'); | |
| 19 | + | |
| 20 | + var Jabber = { | |
| 21 | + debug: true, | |
| 22 | + connection: null, | |
| 23 | + bosh_service: $bosh_service, | |
| 24 | + muc_domain: $muc_domain, | |
| 25 | + muc_supported: false, | |
| 26 | + presence_status: '', | |
| 27 | + conversation_prefix: 'conversation-', | |
| 28 | + conversations_order: null, | |
| 29 | + notification_sound: new Audio('/sounds/receive.wav'), | |
| 30 | + window_visibility: null, | |
| 31 | + jids: {}, | |
| 32 | + rooms: {}, | |
| 33 | + no_more_messages: {}, | |
| 34 | + avatars: {}, | |
| 35 | + | |
| 36 | + template: function(selector) { | |
| 37 | + return $('#chat #chat-templates '+selector).clone().html(); | |
| 38 | + }, | |
| 39 | + | |
| 40 | + jid_to_id: function (jid) { | |
| 41 | + return Strophe.getBareJidFromJid(jid).replace(/@/g, "-").replace(/\./g, "-"); | |
| 42 | + }, | |
| 43 | + | |
| 44 | + jid_of: function(jid_id) { | |
| 45 | + return Jabber.jids[jid_id].jid; | |
| 46 | + }, | |
| 47 | + name_of: function(jid_id) { | |
| 48 | + return Jabber.jids[jid_id].name; | |
| 49 | + }, | |
| 50 | + type_of: function(jid_id) { | |
| 51 | + return Jabber.jids[jid_id].type; | |
| 52 | + }, | |
| 53 | + presence_of: function(jid_id) { | |
| 54 | + return Jabber.jids[jid_id].presence; | |
| 55 | + }, | |
| 56 | + unread_messages_of: function(jid_id, value) { | |
| 57 | + Jabber.jids[jid_id].unread_messages = (value == undefined ? Jabber.jids[jid_id].unread_messages : value); | |
| 58 | + return Jabber.jids[jid_id].unread_messages; | |
| 59 | + }, | |
| 60 | + | |
| 61 | + insert_or_update_user: function (list, item, jid, name, presence, template, type, remove_on_offline) { | |
| 62 | + var jid_id = Jabber.jid_to_id(jid); | |
| 63 | + var identifier = Strophe.getNodeFromJid(jid); | |
| 64 | + var html = template | |
| 65 | + .replace('%{jid_id}', jid_id) | |
| 66 | + .replace(/%{presence_status}/g, presence) | |
| 67 | + .replace('%{avatar}', getAvatar(identifier)) | |
| 68 | + .replace('%{name}', name); | |
| 69 | + | |
| 70 | + $(item).parent().remove(); | |
| 71 | + if(presence != 'offline' || !remove_on_offline){ | |
| 72 | + $(list).append(html); | |
| 73 | + sort_conversations(); | |
| 74 | + } | |
| 75 | + Jabber.jids[jid_id] = {jid: jid, name: name, type: type, presence: presence}; | |
| 76 | + }, | |
| 77 | + insert_or_update_group: function (jid, presence) { | |
| 78 | + var jid_id = Jabber.jid_to_id(jid); | |
| 79 | + var list = $('#buddy-list .buddies ul.'+presence); | |
| 80 | + var item = $('#' + jid_id); | |
| 81 | + presence = presence || ($(item).length > 0 ? $(item).parent('li').attr('class') : 'offline'); | |
| 82 | + log('adding or updating contact ' + jid + ' as ' + presence); | |
| 83 | + Jabber.insert_or_update_user(list, item, jid, Jabber.name_of(jid_id), presence, Jabber.template('.buddy-item'), 'groupchat'); | |
| 84 | + $("#chat-window .tab a[href='#"+ Jabber.conversation_prefix + jid_id +"']") | |
| 85 | + .removeClass() | |
| 86 | + .addClass('icon-menu-' + presence + '-11'); | |
| 87 | + }, | |
| 88 | + insert_or_update_contact: function (jid, name, presence) { | |
| 89 | + var jid_id = Jabber.jid_to_id(jid); | |
| 90 | + var item = $('#' + jid_id); | |
| 91 | + presence = presence || ($(item).length > 0 ? $(item).parent('li').attr('class') : 'offline'); | |
| 92 | + var list = $('#buddy-list .buddies ul' + (presence=='offline' ? '.offline' : '.online')); | |
| 93 | + | |
| 94 | + log('adding or updating contact ' + jid + ' as ' + presence); | |
| 95 | + Jabber.insert_or_update_user(list, item, jid, name, presence, Jabber.template('.buddy-item'), 'chat'); | |
| 96 | + $("#chat-window .tab a[href='#"+ Jabber.conversation_prefix + jid_id +"']") | |
| 97 | + .removeClass() | |
| 98 | + .addClass('icon-menu-' + presence + '-11'); | |
| 99 | + }, | |
| 100 | + insert_or_update_occupant: function (jid, name, presence, room_jid) { | |
| 101 | + log('adding or updating occupant ' + jid + ' as ' + presence); | |
| 102 | + var jid_id = Jabber.jid_to_id(jid); | |
| 103 | + var room_jid_id = Jabber.jid_to_id(room_jid); | |
| 104 | + var list = $('#' + Jabber.conversation_prefix + room_jid_id + ' .occupants ul'); | |
| 105 | + var item = $(list).find('a[data-id='+ jid_id +']'); | |
| 106 | + Jabber.insert_or_update_user(list, item, jid, name, presence, Jabber.template('.occupant-item'), 'chat', true); | |
| 107 | + if (Jabber.rooms[room_jid_id] === undefined) | |
| 108 | + Jabber.rooms[room_jid_id] = {}; | |
| 109 | + | |
| 110 | + var room = Jabber.rooms[room_jid_id]; | |
| 111 | + if(presence == 'offline') { | |
| 112 | + delete Jabber.rooms[room_jid_id][name]; | |
| 113 | + } | |
| 114 | + else { | |
| 115 | + Jabber.rooms[room_jid_id][name] = jid; | |
| 116 | + } | |
| 108 | 117 | |
| 109 | - list.parents('.occupants').find('.occupants-online').text(Object.keys(Jabber.rooms[room_jid_id]).length); | |
| 110 | - }, | |
| 111 | - | |
| 112 | - remove_contact: function(jid) { | |
| 113 | - var jid_id = Jabber.jid_to_id(jid) | |
| 114 | - log('Removing contact ' + jid); | |
| 115 | - $('#' + jid_id).parent('li').remove(); | |
| 116 | - }, | |
| 117 | - | |
| 118 | - render_body_message: function(body) { | |
| 119 | - body = body.replace(/\r?\n/g, '<br>'); | |
| 120 | - body = $().emoticon(body); | |
| 121 | - body = linkify(body, { | |
| 122 | - callback: function(text, href) { | |
| 123 | - return href ? '<a href="' + href + '" title="' + href + '" target="_blank">' + text + '</a>' : text; | |
| 124 | - } | |
| 125 | - }); | |
| 126 | - return body; | |
| 127 | - }, | |
| 118 | + list.parents('.occupants').find('.occupants-online').text(Object.keys(Jabber.rooms[room_jid_id]).length); | |
| 119 | + }, | |
| 120 | + | |
| 121 | + remove_contact: function(jid) { | |
| 122 | + var jid_id = Jabber.jid_to_id(jid) | |
| 123 | + log('Removing contact ' + jid); | |
| 124 | + $('#' + jid_id).parent('li').remove(); | |
| 125 | + }, | |
| 126 | + | |
| 127 | + render_body_message: function(body) { | |
| 128 | + body = body.replace(/\r?\n/g, '<br>'); | |
| 129 | + body = $().emoticon(body); | |
| 130 | + body = linkify(body, { | |
| 131 | + callback: function(text, href) { | |
| 132 | + return href ? '<a href="' + href + '" title="' + href + '" target="_blank">' + text + '</a>' : text; | |
| 133 | + } | |
| 134 | + }); | |
| 135 | + return body; | |
| 136 | + }, | |
| 128 | 137 | |
| 129 | - show_message: function (jid, name, body, who, identifier, time, offset) { | |
| 130 | - if(!offset) offset = 0; | |
| 131 | - if (body) { | |
| 132 | - body = Jabber.render_body_message(body); | |
| 133 | - var jid_id = Jabber.jid_to_id(jid); | |
| 134 | - var tab_id = '#' + Jabber.conversation_prefix + jid_id; | |
| 135 | - var history = $(tab_id).find('.history'); | |
| 138 | + show_message: function (jid, name, body, who, identifier, time, offset) { | |
| 139 | + if(!offset) offset = 0; | |
| 140 | + if (body) { | |
| 141 | + body = Jabber.render_body_message(body); | |
| 142 | + var jid_id = Jabber.jid_to_id(jid); | |
| 143 | + var tab_id = '#' + Jabber.conversation_prefix + jid_id; | |
| 144 | + var history = $(tab_id).find('.history'); | |
| 136 | 145 | |
| 137 | - var offset_container = history.find('.chat-offset-container-'+offset); | |
| 138 | - if(offset_container.length == 0) | |
| 139 | - offset_container = $('<div class="chat-offset-container-'+offset+'"></div>').prependTo(history); | |
| 146 | + var offset_container = history.find('.chat-offset-container-'+offset); | |
| 147 | + if(offset_container.length == 0) | |
| 148 | + offset_container = $('<div class="chat-offset-container-'+offset+'"></div>').prependTo(history); | |
| 140 | 149 | |
| 141 | - if (offset_container.find('.message:last').attr('data-who') == who) { | |
| 142 | - offset_container.find('.message:last .content').append('<p>' + body + '</p>'); | |
| 143 | - } | |
| 144 | - else { | |
| 145 | - if (time==undefined) { | |
| 146 | - time = new Date().toISOString(); | |
| 147 | - } | |
| 148 | - var message_html = Jabber.template('.message') | |
| 149 | - .replace('%{message}', body) | |
| 150 | - .replace(/%{who}/g, who) | |
| 151 | - .replace('%{time}', time) | |
| 152 | - .replace('%{name}', name) | |
| 153 | - .replace('%{avatar}', getAvatar(identifier)); | |
| 154 | - offset_container.append(message_html); | |
| 155 | - $(".message span.time").timeago(); | |
| 156 | - } | |
| 157 | - if(offset == 0) history.scrollTo({top:'100%', left:'0%'}); | |
| 158 | - else history.scrollTo(offset_container.height()); | |
| 159 | - if (who != "self") { | |
| 160 | - if ($(tab_id).find('.history:visible').length == 0) { | |
| 161 | - count_unread_messages(jid_id); | |
| 162 | - } | |
| 163 | - document.alert_title = name; | |
| 164 | - } | |
| 165 | - } | |
| 166 | - }, | |
| 167 | - | |
| 168 | - show_status: function(presence) { | |
| 169 | - log('changing my status to ' + presence); | |
| 170 | - $('#buddy-list .user-status .simplemenu-trigger') | |
| 171 | - .removeClass('icon-menu-chat') | |
| 172 | - .removeClass('icon-menu-offline') | |
| 173 | - .removeClass('icon-menu-dnd') | |
| 174 | - .addClass('icon-menu-' + (presence || 'offline')); | |
| 175 | - $('#buddy-list #user-status img.avatar').replaceWith(getMyAvatar()); | |
| 176 | - $.get('/chat/update_presence_status', { status: {chat_status: presence, last_chat_status: presence} }); | |
| 177 | - }, | |
| 178 | - | |
| 179 | - send_availability_status: function(presence) { | |
| 180 | - log('send availability status ' + presence); | |
| 181 | - Jabber.connection.send($pres().c('show').t(presence).up()); | |
| 182 | - Jabber.show_status(presence); | |
| 183 | - }, | |
| 184 | - | |
| 185 | - enter_room: function(jid, push) { | |
| 186 | - if(push == undefined) | |
| 187 | - push = true | |
| 188 | - var jid_id = Jabber.jid_to_id(jid); | |
| 189 | - var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 190 | - var button = $('#' + conversation_id + ' .join'); | |
| 191 | - button.hide(); | |
| 192 | - button.siblings('.leave').show(); | |
| 193 | - Jabber.connection.send( | |
| 194 | - $pres({to: jid + '/' + $own_name}).c('x', {xmlns: Strophe.NS.MUC}).c('history', {maxchars: 0}) | |
| 195 | - ); | |
| 196 | - Jabber.insert_or_update_group(jid, 'online'); | |
| 150 | + if (offset_container.find('.message:last').attr('data-who') == who) { | |
| 151 | + offset_container.find('.message:last .content').append('<p>' + body + '</p>'); | |
| 152 | + } | |
| 153 | + else { | |
| 154 | + if (time==undefined) { | |
| 155 | + time = new Date().toISOString(); | |
| 156 | + } | |
| 157 | + var message_html = Jabber.template('.message') | |
| 158 | + .replace('%{message}', body) | |
| 159 | + .replace(/%{who}/g, who) | |
| 160 | + .replace('%{time}', time) | |
| 161 | + .replace('%{name}', name) | |
| 162 | + .replace('%{avatar}', getAvatar(identifier)); | |
| 163 | + offset_container.append(message_html); | |
| 164 | + $(".message span.time").timeago(); | |
| 165 | + } | |
| 166 | + if(offset == 0) history.scrollTo({top:'100%', left:'0%'}); | |
| 167 | + else history.scrollTo(offset_container.height()); | |
| 168 | + if (who != "self") { | |
| 169 | + if ($(tab_id).find('.history:visible').length == 0) { | |
| 170 | + count_unread_messages(jid_id); | |
| 171 | + } | |
| 172 | + document.alert_title = name; | |
| 173 | + } | |
| 174 | + } | |
| 175 | + }, | |
| 176 | + | |
| 177 | + show_status: function(presence) { | |
| 178 | + log('changing my status to ' + presence); | |
| 179 | + $('#buddy-list .user-status .simplemenu-trigger') | |
| 180 | + .removeClass('icon-menu-chat') | |
| 181 | + .removeClass('icon-menu-offline') | |
| 182 | + .removeClass('icon-menu-dnd') | |
| 183 | + .addClass('icon-menu-' + (presence || 'offline')); | |
| 184 | + $('#buddy-list #user-status img.avatar').replaceWith(getMyAvatar()); | |
| 185 | + $.get('/chat/update_presence_status', { status: {chat_status: presence, last_chat_status: presence} }); | |
| 186 | + }, | |
| 187 | + | |
| 188 | + send_availability_status: function(presence) { | |
| 189 | + log('send availability status ' + presence); | |
| 190 | + Jabber.connection.send($pres().c('show').t(presence).up()); | |
| 191 | + Jabber.show_status(presence); | |
| 192 | + }, | |
| 193 | + | |
| 194 | + enter_room: function(jid, push) { | |
| 195 | + if(push == undefined) | |
| 196 | + push = true | |
| 197 | + var jid_id = Jabber.jid_to_id(jid); | |
| 198 | + var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 199 | + var button = $('#' + conversation_id + ' .join'); | |
| 200 | + button.hide(); | |
| 201 | + button.siblings('.leave').show(); | |
| 202 | + Jabber.connection.send( | |
| 203 | + $pres({to: jid + '/' + $own_name}).c('x', {xmlns: Strophe.NS.MUC}).c('history', {maxchars: 0}) | |
| 204 | + ); | |
| 205 | + Jabber.insert_or_update_group(jid, 'online'); | |
| 206 | + Jabber.update_chat_title(); | |
| 207 | + sort_conversations(); | |
| 208 | + if(push) | |
| 209 | + $.post('/chat/join', {room_id: jid}); | |
| 210 | + }, | |
| 211 | + | |
| 212 | + leave_room: function(jid, push) { | |
| 213 | + if(push == undefined) | |
| 214 | + push = true | |
| 215 | + var jid_id = Jabber.jid_to_id(jid); | |
| 216 | + var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 217 | + var button = $('#' + conversation_id + ' .leave'); | |
| 218 | + button.hide(); | |
| 219 | + button.siblings('.join').show(); | |
| 220 | + Jabber.connection.send($pres({from: Jabber.connection.jid, to: jid + '/' + $own_name, type: 'unavailable'})) | |
| 221 | + Jabber.insert_or_update_group(jid, 'offline'); | |
| 222 | + sort_conversations(); | |
| 223 | + if(push) | |
| 224 | + $.post('/chat/leave', {room_id: jid}); | |
| 225 | + }, | |
| 226 | + | |
| 227 | + update_chat_title: function () { | |
| 228 | + var friends_online = $('#buddy-list #friends .buddy-list.online li').length; | |
| 229 | + $('#friends-online').text(friends_online); | |
| 230 | + var friends_offline = $('#buddy-list #friends .buddy-list.offline li').length; | |
| 231 | + $('#friends-offline').text(friends_offline); | |
| 232 | + var groups_online = $('#buddy-list #rooms .buddy-list li').length; | |
| 233 | + $('#groups-online').text(groups_online); | |
| 234 | + }, | |
| 235 | + | |
| 236 | + on_connect: function (status) { | |
| 237 | + switch (status) { | |
| 238 | + case Strophe.Status.CONNECTING: | |
| 239 | + log('connecting...'); | |
| 240 | + break; | |
| 241 | + case Strophe.Status.CONNFAIL: | |
| 242 | + log('failed to connect'); | |
| 243 | + setTimeout(function(){Jabber.connect()}, 10000); | |
| 244 | + break; | |
| 245 | + case Strophe.Status.DISCONNECTING: | |
| 246 | + log('disconnecting...'); | |
| 247 | + $('#buddy-list .toolbar').addClass('small-loading-dark'); | |
| 248 | + break; | |
| 249 | + case Strophe.Status.DISCONNECTED: | |
| 250 | + log('disconnected'); | |
| 251 | + $('#buddy-list ul.buddy-list, .occupants ul.occupant-list').html(''); | |
| 197 | 252 | Jabber.update_chat_title(); |
| 198 | - sort_conversations(); | |
| 199 | - if(push) | |
| 200 | - $.post('/chat/join', {room_id: jid}); | |
| 201 | - }, | |
| 202 | - | |
| 203 | - leave_room: function(jid, push) { | |
| 204 | - if(push == undefined) | |
| 205 | - push = true | |
| 253 | + $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 254 | + $('textarea').prop('disabled', 'disabled'); | |
| 255 | + if(Jabber.presence_status != 'offline') | |
| 256 | + Jabber.connect(); | |
| 257 | + break; | |
| 258 | + case Strophe.Status.CONNECTED: | |
| 259 | + log('connected'); | |
| 260 | + case Strophe.Status.ATTACHED: | |
| 261 | + log('XMPP/BOSH session attached'); | |
| 262 | + $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 263 | + $('textarea').prop('disabled', ''); | |
| 264 | + break; | |
| 265 | + } | |
| 266 | + }, | |
| 267 | + | |
| 268 | + on_roster: function (iq) { | |
| 269 | + log('receiving roster'); | |
| 270 | + var profiles = []; | |
| 271 | + var contacts_to_insert = {}; | |
| 272 | + var groups_to_insert = []; | |
| 273 | + | |
| 274 | + $(iq).find('item').each(function () { | |
| 275 | + var jid = $(this).attr('jid'); | |
| 276 | + profiles.push(getIdentifier(jid)); | |
| 277 | + var name = $(this).attr('name') || jid; | |
| 206 | 278 | var jid_id = Jabber.jid_to_id(jid); |
| 207 | - var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 208 | - var button = $('#' + conversation_id + ' .leave'); | |
| 209 | - button.hide(); | |
| 210 | - button.siblings('.join').show(); | |
| 211 | - Jabber.connection.send($pres({from: Jabber.connection.jid, to: jid + '/' + $own_name, type: 'unavailable'})) | |
| 212 | - Jabber.insert_or_update_group(jid, 'offline'); | |
| 213 | - sort_conversations(); | |
| 214 | - if(push) | |
| 215 | - $.post('/chat/leave', {room_id: jid}); | |
| 216 | - }, | |
| 217 | - | |
| 218 | - update_chat_title: function () { | |
| 219 | - var friends_online = $('#buddy-list #friends .buddy-list.online li').length; | |
| 220 | - $('#friends-online').text(friends_online); | |
| 221 | - var friends_offline = $('#buddy-list #friends .buddy-list.offline li').length; | |
| 222 | - $('#friends-offline').text(friends_offline); | |
| 223 | - var groups_online = $('#buddy-list #rooms .buddy-list li').length; | |
| 224 | - $('#groups-online').text(groups_online); | |
| 225 | - }, | |
| 226 | - | |
| 227 | - on_connect: function (status) { | |
| 228 | - switch (status) { | |
| 229 | - case Strophe.Status.CONNECTING: | |
| 230 | - log('connecting...'); | |
| 231 | - break; | |
| 232 | - case Strophe.Status.CONNFAIL: | |
| 233 | - log('failed to connect'); | |
| 234 | - break; | |
| 235 | - case Strophe.Status.DISCONNECTING: | |
| 236 | - log('disconnecting...'); | |
| 237 | - $('#buddy-list .toolbar').addClass('small-loading-dark'); | |
| 238 | - break; | |
| 239 | - case Strophe.Status.DISCONNECTED: | |
| 240 | - log('disconnected'); | |
| 241 | - $('#buddy-list ul.buddy-list, .occupants ul.occupant-list').html(''); | |
| 242 | - Jabber.update_chat_title(); | |
| 243 | - $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 244 | - $('textarea').prop('disabled', 'disabled'); | |
| 245 | - break; | |
| 246 | - case Strophe.Status.CONNECTED: | |
| 247 | - log('connected'); | |
| 248 | - case Strophe.Status.ATTACHED: | |
| 249 | - log('XMPP/BOSH session attached'); | |
| 250 | - $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 251 | - $('textarea').prop('disabled', ''); | |
| 252 | - break; | |
| 253 | - } | |
| 254 | - }, | |
| 255 | - | |
| 256 | - on_roster: function (iq) { | |
| 257 | - log('receiving roster'); | |
| 258 | - $(iq).find('item').each(function () { | |
| 259 | - var jid = $(this).attr('jid'); | |
| 260 | - var name = $(this).attr('name') || jid; | |
| 261 | - var jid_id = Jabber.jid_to_id(jid); | |
| 262 | - Jabber.insert_or_update_contact(jid, name); | |
| 263 | - }); | |
| 264 | - //TODO Add groups through roster too... | |
| 265 | - $.ajax({ | |
| 266 | - url: '/chat/roster_groups', | |
| 267 | - dataType: 'json', | |
| 268 | - success: function(data){ | |
| 269 | - data.each(function(room){ | |
| 270 | - var jid_id = Jabber.jid_to_id(room.jid); | |
| 271 | - Jabber.jids[jid_id] = {jid: room.jid, name: room.name, type: 'groupchat'}; | |
| 272 | - //FIXME This must check on session if the user is inside the room... | |
| 273 | - Jabber.insert_or_update_group(room.jid, 'offline'); | |
| 279 | + contacts_to_insert[jid] = name; | |
| 280 | + }); | |
| 281 | + | |
| 282 | + //TODO Add groups through roster too... | |
| 283 | + $.ajax({ | |
| 284 | + url: '/chat/roster_groups', | |
| 285 | + dataType: 'json', | |
| 286 | + success: function(data){ | |
| 287 | + $(data).each(function(index, room){ | |
| 288 | + profiles.push(getIdentifier(room.jid)); | |
| 289 | + var jid_id = Jabber.jid_to_id(room.jid); | |
| 290 | + Jabber.jids[jid_id] = {jid: room.jid, name: room.name, type: 'groupchat'}; | |
| 291 | + //FIXME This must check on session if the user is inside the room... | |
| 292 | + groups_to_insert.push(room.jid); | |
| 293 | + | |
| 294 | + }); | |
| 295 | + $.getJSON('/chat/avatars', {profiles: profiles}, function(data) { | |
| 296 | + for(identifier in data) | |
| 297 | + Jabber.avatars[identifier] = data[identifier]; | |
| 298 | + | |
| 299 | + // Insert contacts | |
| 300 | + for(contact_jid in contacts_to_insert) | |
| 301 | + Jabber.insert_or_update_contact(contact_jid, contacts_to_insert[contact_jid]); | |
| 302 | + | |
| 303 | + // Insert groups | |
| 304 | + for (var i = 0; i < groups_to_insert.length; i++) | |
| 305 | + Jabber.insert_or_update_group(groups_to_insert[i], 'offline'); | |
| 306 | + | |
| 307 | + $.getJSON('/chat/recent_conversations', {}, function(data) { | |
| 308 | + Jabber.conversations_order = data; | |
| 309 | + sort_conversations(); | |
| 274 | 310 | }); |
| 275 | - }, | |
| 276 | - error: function(data, textStatus, jqXHR){ | |
| 277 | - console.log(data); | |
| 278 | - }, | |
| 279 | - }); | |
| 280 | - sort_conversations(); | |
| 281 | - // set up presence handler and send initial presence | |
| 282 | - Jabber.connection.addHandler(Jabber.on_presence, null, "presence"); | |
| 283 | - Jabber.send_availability_status(Jabber.presence_status); | |
| 284 | - load_defaults(); | |
| 285 | - }, | |
| 286 | - | |
| 287 | - // NOTE: cause Noosfero store's rosters in database based on friendship relation between people | |
| 288 | - // these event never occurs cause jabber service (ejabberd) didn't know when a roster was changed | |
| 289 | - on_roster_changed: function (iq) { | |
| 290 | - log('roster changed'); | |
| 291 | - $(iq).find('item').each(function () { | |
| 292 | - var sub = $(this).attr('subscription'); | |
| 293 | - var jid = $(this).attr('jid'); | |
| 294 | - var name = $(this).attr('name') || jid; | |
| 295 | - if (sub == 'remove') { | |
| 296 | - // contact is being removed | |
| 297 | - Jabber.remove_contact(jid); | |
| 298 | - } else { | |
| 299 | - // contact is being added or modified | |
| 300 | - Jabber.insert_or_update_contact(jid, name); | |
| 301 | - } | |
| 302 | - }); | |
| 303 | - return true; | |
| 304 | - }, | |
| 305 | - | |
| 306 | - parse: function (stanza) { | |
| 307 | - var result = {}; | |
| 308 | - if (Strophe.isTagEqual(stanza, 'presence')) { | |
| 309 | - result.from = $(stanza).attr('from'); | |
| 310 | - result.type = $(stanza).attr('type'); | |
| 311 | - if (result.type == 'unavailable') { | |
| 312 | - result.show = 'offline'; | |
| 313 | - } else { | |
| 314 | - var show = $(stanza).find("show").text(); | |
| 315 | - if (show === "" || show == "chat") { | |
| 316 | - result.show = 'chat'; | |
| 317 | - } | |
| 318 | - else if (show == "dnd" || show == "xa") { | |
| 319 | - result.show = 'dnd'; | |
| 320 | - } | |
| 321 | - else { | |
| 322 | - result.show = 'away'; | |
| 323 | - } | |
| 324 | - } | |
| 325 | - if ($(stanza).find('x[xmlns="'+ Strophe.NS.MUC_USER +'"]').length > 0) { | |
| 326 | - result.is_from_room = true; | |
| 327 | - result.from_user = $(stanza).find('x item').attr('jid'); | |
| 328 | - if ($(stanza).find('x item').attr('affiliation') == 'owner') { | |
| 329 | - result.awaiting_configuration = ($(stanza).find('x status').attr('code') == '201'); | |
| 330 | - } | |
| 331 | - } | |
| 311 | + | |
| 312 | + // set up presence handler and send initial presence | |
| 313 | + Jabber.connection.addHandler(Jabber.on_presence, null, "presence"); | |
| 314 | + Jabber.send_availability_status(Jabber.presence_status); | |
| 315 | + load_defaults(); | |
| 316 | + }); | |
| 317 | + }, | |
| 318 | + error: function(data, textStatus, jqXHR){ | |
| 319 | + console.log(data); | |
| 320 | + }, | |
| 321 | + }); | |
| 322 | + | |
| 323 | + }, | |
| 324 | + | |
| 325 | + // NOTE: cause Noosfero store's rosters in database based on friendship relation between people | |
| 326 | + // these event never occurs cause jabber service (ejabberd) didn't know when a roster was changed | |
| 327 | + on_roster_changed: function (iq) { | |
| 328 | + log('roster changed'); | |
| 329 | + $(iq).find('item').each(function () { | |
| 330 | + var sub = $(this).attr('subscription'); | |
| 331 | + var jid = $(this).attr('jid'); | |
| 332 | + var name = $(this).attr('name') || jid; | |
| 333 | + if (sub == 'remove') { | |
| 334 | + // contact is being removed | |
| 335 | + Jabber.remove_contact(jid); | |
| 336 | + } else { | |
| 337 | + // contact is being added or modified | |
| 338 | + Jabber.insert_or_update_contact(jid, name); | |
| 332 | 339 | } |
| 333 | - else if (Strophe.isTagEqual(stanza, 'message')) { | |
| 334 | - result.from = $(stanza).attr('from'); | |
| 335 | - result.body = $(stanza).find('body').text(); | |
| 336 | - if ($(stanza).find('error').length > 0) { | |
| 337 | - result.error = $(stanza).find('error text').text(); | |
| 338 | - if (!result.error && $(stanza).find('error').find('service-unavailable').length > 0) { | |
| 339 | - result.error = $user_unavailable_error; | |
| 340 | - } | |
| 341 | - } | |
| 340 | + }); | |
| 341 | + return true; | |
| 342 | + }, | |
| 343 | + | |
| 344 | + parse: function (stanza) { | |
| 345 | + var result = {}; | |
| 346 | + if (Strophe.isTagEqual(stanza, 'presence')) { | |
| 347 | + result.from = $(stanza).attr('from'); | |
| 348 | + result.type = $(stanza).attr('type'); | |
| 349 | + if (result.type == 'unavailable') { | |
| 350 | + result.show = 'offline'; | |
| 351 | + } else { | |
| 352 | + var show = $(stanza).find("show").text(); | |
| 353 | + if (show === "" || show == "chat") { | |
| 354 | + result.show = 'chat'; | |
| 355 | + } | |
| 356 | + else if (show == "dnd" || show == "xa") { | |
| 357 | + result.show = 'dnd'; | |
| 358 | + } | |
| 359 | + else { | |
| 360 | + result.show = 'away'; | |
| 361 | + } | |
| 342 | 362 | } |
| 343 | - return result; | |
| 344 | - }, | |
| 345 | - | |
| 346 | - on_presence: function (presence) { | |
| 347 | - presence = Jabber.parse(presence); | |
| 348 | - if (presence.type != 'error') { | |
| 349 | - if (presence.is_from_room) { | |
| 350 | - log('receiving room presence from ' + presence.from + ' as ' + presence.show); | |
| 351 | - var name = Strophe.getResourceFromJid(presence.from); | |
| 352 | - if (presence.from_user) { | |
| 353 | - Jabber.insert_or_update_occupant(presence.from_user, name, presence.show, presence.from); | |
| 354 | - } | |
| 355 | - else { | |
| 356 | - log('ooops! user jid not found in presence stanza'); | |
| 357 | - } | |
| 358 | - if (presence.awaiting_configuration) { | |
| 359 | - log('sending instant room configuration to ' + Strophe.getBareJidFromJid(presence.from)); | |
| 360 | - Jabber.connection.sendIQ( | |
| 361 | - $iq({type: 'set', to: Strophe.getBareJidFromJid(presence.from)}) | |
| 362 | - .c('query', {xmlns: Strophe.NS.MUC_OWNER}) | |
| 363 | - .c('x', {xmlns: Strophe.NS.DATA_FORMS, type: 'submit'}) | |
| 364 | - ); | |
| 365 | - } | |
| 366 | - } | |
| 367 | - else { | |
| 368 | - log('receiving contact presence from ' + presence.from + ' as ' + presence.show); | |
| 369 | - var jid = Strophe.getBareJidFromJid(presence.from); | |
| 370 | - if (jid != Jabber.connection.jid) { | |
| 371 | - var name = Jabber.name_of(Jabber.jid_to_id(jid)); | |
| 372 | - Jabber.insert_or_update_contact(jid, name, presence.show); | |
| 373 | - Jabber.update_chat_title(); | |
| 374 | - } | |
| 375 | - else { | |
| 376 | - // why server sends presence from myself to me? | |
| 377 | - log('ignoring presence from myself'); | |
| 378 | - if(presence.show=='offline') { | |
| 379 | - console.log(Jabber.presence_status); | |
| 380 | - Jabber.send_availability_status(Jabber.presence_status); | |
| 381 | - } | |
| 382 | - } | |
| 383 | - } | |
| 363 | + if ($(stanza).find('x[xmlns="'+ Strophe.NS.MUC_USER +'"]').length > 0) { | |
| 364 | + result.is_from_room = true; | |
| 365 | + result.from_user = $(stanza).find('x item').attr('jid'); | |
| 366 | + if ($(stanza).find('x item').attr('affiliation') == 'owner') { | |
| 367 | + result.awaiting_configuration = ($(stanza).find('x status').attr('code') == '201'); | |
| 368 | + } | |
| 384 | 369 | } |
| 385 | - return true; | |
| 386 | - }, | |
| 387 | - | |
| 388 | - on_private_message: function (message) { | |
| 389 | - message = Jabber.parse(message); | |
| 390 | - log('receiving message from ' + message.from); | |
| 391 | - var jid = Strophe.getBareJidFromJid(message.from); | |
| 392 | - var jid_id = Jabber.jid_to_id(jid); | |
| 393 | - var name = Jabber.name_of(jid_id); | |
| 394 | - create_conversation_tab(name, jid_id); | |
| 395 | - Jabber.show_message(jid, name, escape_html(message.body), 'other', Strophe.getNodeFromJid(jid)); | |
| 396 | - notifyMessage(message); | |
| 397 | - return true; | |
| 398 | - }, | |
| 399 | - | |
| 400 | - on_public_message: function (message) { | |
| 401 | - message = Jabber.parse(message); | |
| 402 | - log('receiving message from ' + message.from); | |
| 403 | - var name = Strophe.getResourceFromJid(message.from); | |
| 404 | - // is a message from the room itself | |
| 405 | - if (! name) { | |
| 406 | - Jabber.show_notice(Jabber.jid_to_id(message.from), message.body); | |
| 407 | - } | |
| 408 | - // is a message from another user, not mine | |
| 409 | - else if ($own_name != name) { | |
| 410 | - var jid = Jabber.rooms[Jabber.jid_to_id(message.from)][name]; | |
| 411 | - Jabber.show_message(message.from, name, escape_html(message.body), name, Strophe.getNodeFromJid(jid)); | |
| 370 | + } | |
| 371 | + else if (Strophe.isTagEqual(stanza, 'message')) { | |
| 372 | + result.from = $(stanza).attr('from'); | |
| 373 | + result.body = $(stanza).find('body').text(); | |
| 374 | + if ($(stanza).find('error').length > 0) { | |
| 375 | + result.error = $(stanza).find('error text').text(); | |
| 376 | + if (!result.error && $(stanza).find('error').find('service-unavailable').length > 0) { | |
| 377 | + result.error = $user_unavailable_error; | |
| 378 | + } | |
| 412 | 379 | } |
| 413 | - notifyMessage(message); | |
| 414 | - return true; | |
| 415 | - }, | |
| 416 | - | |
| 417 | - on_message_error: function (message) { | |
| 418 | - message = Jabber.parse(message) | |
| 419 | - var jid = Strophe.getBareJidFromJid(message.from); | |
| 420 | - log('Receiving error message from ' + jid); | |
| 421 | - var body = Jabber.template('.error-message').replace('%{text}', message.error); | |
| 422 | - Jabber.show_message(jid, Jabber.name_of(Jabber.jid_to_id(jid)), body, 'other', Strophe.getNodeFromJid(jid)); | |
| 423 | - return true; | |
| 424 | - }, | |
| 425 | - | |
| 426 | - on_muc_support: function(iq) { | |
| 427 | - if ($(iq).find('identity[category=conference]').length > 0 && $(iq).find('feature[var="'+ Strophe.NS.MUC +'"]').length > 0) { | |
| 428 | - var name = $(iq).find('identity[category=conference]').attr('name'); | |
| 429 | - log('muc support found with identity '+ name); | |
| 430 | - Jabber.muc_supported = true; | |
| 380 | + } | |
| 381 | + return result; | |
| 382 | + }, | |
| 383 | + | |
| 384 | + on_presence: function (presence) { | |
| 385 | + presence = Jabber.parse(presence); | |
| 386 | + if (presence.type != 'error') { | |
| 387 | + if (presence.is_from_room) { | |
| 388 | + log('receiving room presence from ' + presence.from + ' as ' + presence.show); | |
| 389 | + var name = Strophe.getResourceFromJid(presence.from); | |
| 390 | + if (presence.from_user) { | |
| 391 | + Jabber.insert_or_update_occupant(presence.from_user, name, presence.show, presence.from); | |
| 392 | + } | |
| 393 | + else { | |
| 394 | + log('ooops! user jid not found in presence stanza'); | |
| 395 | + } | |
| 396 | + if (presence.awaiting_configuration) { | |
| 397 | + log('sending instant room configuration to ' + Strophe.getBareJidFromJid(presence.from)); | |
| 398 | + Jabber.connection.sendIQ( | |
| 399 | + $iq({type: 'set', to: Strophe.getBareJidFromJid(presence.from)}) | |
| 400 | + .c('query', {xmlns: Strophe.NS.MUC_OWNER}) | |
| 401 | + .c('x', {xmlns: Strophe.NS.DATA_FORMS, type: 'submit'}) | |
| 402 | + ); | |
| 403 | + } | |
| 431 | 404 | } |
| 432 | 405 | else { |
| 433 | - log('muc support not found'); | |
| 406 | + log('receiving contact presence from ' + presence.from + ' as ' + presence.show); | |
| 407 | + var jid = Strophe.getBareJidFromJid(presence.from); | |
| 408 | + if (jid != Jabber.connection.jid) { | |
| 409 | + var jid_id = Jabber.jid_to_id(jid); | |
| 410 | + var name = Jabber.name_of(jid_id); | |
| 411 | + if(presence.show == 'chat') | |
| 412 | + Jabber.remove_notice(jid_id); | |
| 413 | + Jabber.insert_or_update_contact(jid, name, presence.show); | |
| 414 | + Jabber.update_chat_title(); | |
| 415 | + } | |
| 416 | + else { | |
| 417 | + // why server sends presence from myself to me? | |
| 418 | + log('ignoring presence from myself'); | |
| 419 | + if(presence.show=='offline') { | |
| 420 | + Jabber.send_availability_status(Jabber.presence_status); | |
| 421 | + } | |
| 422 | + } | |
| 434 | 423 | } |
| 435 | - }, | |
| 424 | + } | |
| 425 | + return true; | |
| 426 | + }, | |
| 436 | 427 | |
| 437 | - attach_connection: function(data) { | |
| 438 | - // create the connection and attach it | |
| 439 | - Jabber.connection = new Strophe.Connection(Jabber.bosh_service); | |
| 440 | - Jabber.connection.attach(data.jid, data.sid, data.rid, Jabber.on_connect); | |
| 428 | + on_private_message: function (message) { | |
| 429 | + message = Jabber.parse(message); | |
| 430 | + log('receiving message from ' + message.from); | |
| 431 | + var jid = Strophe.getBareJidFromJid(message.from); | |
| 432 | + var jid_id = Jabber.jid_to_id(jid); | |
| 433 | + var name = Jabber.name_of(jid_id); | |
| 434 | + create_conversation_tab(name, jid_id); | |
| 435 | + Jabber.show_message(jid, name, escape_html(message.body), 'other', Strophe.getNodeFromJid(jid)); | |
| 436 | + renew_conversation_order(jid); | |
| 437 | + notifyMessage(message); | |
| 438 | + return true; | |
| 439 | + }, | |
| 440 | + | |
| 441 | + on_public_message: function (message) { | |
| 442 | + message = Jabber.parse(message); | |
| 443 | + log('receiving message from ' + message.from); | |
| 444 | + var name = Strophe.getResourceFromJid(message.from); | |
| 445 | + // is a message from the room itself | |
| 446 | + if (! name) { | |
| 447 | + // FIXME Ignoring message from room for now. | |
| 448 | + // Jabber.show_notice(Jabber.jid_to_id(message.from), message.body); | |
| 449 | + } | |
| 450 | + // is a message from another user, not mine | |
| 451 | + else if ($own_name != name) { | |
| 452 | + var jid = Jabber.rooms[Jabber.jid_to_id(message.from)][name]; | |
| 453 | + Jabber.show_message(message.from, name, escape_html(message.body), name, Strophe.getNodeFromJid(jid)); | |
| 454 | + renew_conversation_order(jid); | |
| 455 | + notifyMessage(message); | |
| 456 | + } | |
| 457 | + return true; | |
| 458 | + }, | |
| 441 | 459 | |
| 442 | - // handle get roster list (buddy list) | |
| 443 | - Jabber.connection.sendIQ($iq({type: 'get'}).c('query', {xmlns: Strophe.NS.ROSTER}), Jabber.on_roster); | |
| 460 | + on_message_error: function (message) { | |
| 461 | + }, | |
| 444 | 462 | |
| 445 | - // handle presence updates in roster list | |
| 446 | - Jabber.connection.addHandler(Jabber.on_roster_changed, 'jabber:iq:roster', 'iq', 'set'); | |
| 463 | + on_muc_support: function(iq) { | |
| 464 | + if ($(iq).find('identity[category=conference]').length > 0 && $(iq).find('feature[var="'+ Strophe.NS.MUC +'"]').length > 0) { | |
| 465 | + var name = $(iq).find('identity[category=conference]').attr('name'); | |
| 466 | + log('muc support found with identity '+ name); | |
| 467 | + Jabber.muc_supported = true; | |
| 468 | + } | |
| 469 | + else { | |
| 470 | + log('muc support not found'); | |
| 471 | + } | |
| 472 | + }, | |
| 447 | 473 | |
| 448 | - // Handle messages | |
| 449 | - Jabber.connection.addHandler(Jabber.on_private_message, null, "message", "chat"); | |
| 474 | + attach_connection: function(data) { | |
| 475 | + // create the connection and attach it | |
| 476 | + Jabber.connection = new Strophe.Connection(Jabber.bosh_service); | |
| 477 | + Jabber.connection.attach(data.jid, data.sid, data.rid, Jabber.on_connect); | |
| 450 | 478 | |
| 451 | - // Handle conference messages | |
| 452 | - Jabber.connection.addHandler(Jabber.on_public_message, null, "message", "groupchat"); | |
| 479 | + // handle get roster list (buddy list) | |
| 480 | + Jabber.connection.sendIQ($iq({type: 'get'}).c('query', {xmlns: Strophe.NS.ROSTER}), Jabber.on_roster); | |
| 453 | 481 | |
| 454 | - // Handle message errors | |
| 455 | - Jabber.connection.addHandler(Jabber.on_message_error, null, "message", "error"); | |
| 482 | + // handle presence updates in roster list | |
| 483 | + Jabber.connection.addHandler(Jabber.on_roster_changed, 'jabber:iq:roster', 'iq', 'set'); | |
| 456 | 484 | |
| 457 | - // discovering MUC support | |
| 458 | - Jabber.connection.sendIQ( | |
| 459 | - $iq({type: 'get', from: Jabber.connection.jid, to: Jabber.muc_domain}) | |
| 460 | - .c('query', {xmlns: Strophe.NS.DISCO_INFO}), | |
| 461 | - Jabber.on_muc_support | |
| 462 | - ); | |
| 485 | + // Handle messages | |
| 486 | + Jabber.connection.addHandler(Jabber.on_private_message, null, "message", "chat"); | |
| 463 | 487 | |
| 464 | - // uncomment for extra debugging | |
| 465 | - //Strophe.log = function (lvl, msg) { log(msg); }; | |
| 466 | - }, | |
| 488 | + // Handle conference messages | |
| 489 | + Jabber.connection.addHandler(Jabber.on_public_message, null, "message", "groupchat"); | |
| 467 | 490 | |
| 468 | - connect: function() { | |
| 469 | - if (Jabber.connection && Jabber.connection.connected) { | |
| 470 | - Jabber.send_availability_status(Jabber.presence_status); | |
| 471 | - } | |
| 472 | - else { | |
| 473 | - log('starting XMPP/BOSH session...'); | |
| 474 | - $('#buddy-list .toolbar').removeClass('small-loading-dark').addClass('small-loading-dark'); | |
| 475 | - $('.dialog-error').hide(); | |
| 476 | - $.ajax({ | |
| 477 | - url: '/chat/start_session', | |
| 478 | - dataType: 'json', | |
| 479 | - success: function(data) { | |
| 480 | - Jabber.attach_connection(data) | |
| 481 | - }, | |
| 482 | - error: function(error) { | |
| 483 | - $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 484 | - $('#buddy-list .dialog-error') | |
| 485 | - .html(error.responseText) | |
| 486 | - .show('highlight') | |
| 487 | - .unbind('click') | |
| 488 | - .click(function() { $(this).hide('highlight'); }); | |
| 489 | - } | |
| 490 | - }); | |
| 491 | - } | |
| 492 | - }, | |
| 493 | - | |
| 494 | - deliver_message: function(jid, body) { | |
| 495 | - var type = Jabber.type_of(Jabber.jid_to_id(jid)); | |
| 496 | - var message = $msg({to: jid, from: Jabber.connection.jid, "type": type}) | |
| 497 | - .c('body').t(body).up() | |
| 498 | - .c('active', {xmlns: Strophe.NS.CHAT_STATES}); | |
| 499 | - Jabber.connection.send(message); | |
| 500 | - Jabber.show_message(jid, $own_name, escape_html(body), 'self', Strophe.getNodeFromJid(Jabber.connection.jid)); | |
| 501 | - move_conversation_to_the_top(jid); | |
| 502 | - }, | |
| 503 | - | |
| 504 | - is_a_room: function(jid_id) { | |
| 505 | - return Jabber.type_of(jid_id) == 'groupchat'; | |
| 506 | - }, | |
| 507 | - | |
| 508 | - show_notice: function(jid_id, msg) { | |
| 509 | - var tab_id = '#' + Jabber.conversation_prefix + jid_id; | |
| 510 | - var notice = $(tab_id).find('.history .notice'); | |
| 511 | - if (notice.length > 0) | |
| 512 | - notice.html(msg) | |
| 513 | - else | |
| 514 | - $(tab_id).find('.history').append("<span class='notice'>" + msg + "</span>"); | |
| 515 | - } | |
| 516 | - }; | |
| 517 | - | |
| 518 | - $('#chat-connect').live('click', function() { | |
| 519 | - Jabber.presence_status = 'chat'; | |
| 520 | - Jabber.connect(); | |
| 521 | - }); | |
| 522 | - | |
| 523 | - $('#chat-disconnect').click(function() { | |
| 524 | - disconnect(); | |
| 525 | - }); | |
| 526 | - | |
| 527 | - $('#chat-busy').click(function() { | |
| 528 | - Jabber.presence_status = 'dnd'; | |
| 529 | - Jabber.connect(); | |
| 530 | - }); | |
| 531 | - | |
| 532 | - $('#chat-retry').live('click', function() { | |
| 533 | - Jabber.presence_status = Jabber.presence_status || 'chat'; | |
| 534 | - Jabber.connect(); | |
| 535 | - }); | |
| 536 | - | |
| 537 | - $('.conversation textarea').live('keydown', function(e) { | |
| 538 | - if (e.keyCode == 13) { | |
| 539 | - var jid = $(this).attr('data-to'); | |
| 540 | - var body = $(this).val(); | |
| 541 | - body = body.stripScripts(); | |
| 542 | - save_message(jid, body); | |
| 543 | - Jabber.deliver_message(jid, body); | |
| 544 | - $(this).val(''); | |
| 545 | - return false; | |
| 546 | - } | |
| 547 | - }); | |
| 548 | - | |
| 549 | - function save_message(jid, body) { | |
| 550 | - $.post('/chat/save_message', { | |
| 551 | - to: getIdentifier(jid), | |
| 552 | - body: body | |
| 553 | - }); | |
| 554 | - } | |
| 491 | + // Handle message errors | |
| 492 | + Jabber.connection.addHandler(Jabber.on_message_error, null, "message", "error"); | |
| 555 | 493 | |
| 556 | - // open new conversation or change to already opened tab | |
| 557 | - $('#buddy-list .buddies li a').live('click', function() { | |
| 558 | - var jid_id = $(this).attr('id'); | |
| 559 | - var name = Jabber.name_of(jid_id); | |
| 560 | - var conversation = create_conversation_tab(name, jid_id); | |
| 561 | - | |
| 562 | - $('.conversation').hide(); | |
| 563 | - conversation.show(); | |
| 564 | - count_unread_messages(jid_id, true); | |
| 565 | - if(conversation.find('.chat-offset-container-0').length == 0) | |
| 566 | - recent_messages(Jabber.jid_of(jid_id)); | |
| 567 | - conversation.find('.conversation .input-div textarea.input').focus(); | |
| 568 | - $.post('/chat/tab', {tab_id: jid_id}); | |
| 569 | - }); | |
| 570 | - | |
| 571 | - // put name into text area when click in one occupant | |
| 572 | - $('.occupants .occupant-list li a').live('click', function() { | |
| 573 | - var jid_id = $(this).attr('data-id'); | |
| 574 | - var name = Jabber.name_of(jid_id); | |
| 575 | - var val = $('.conversation textarea:visible').val(); | |
| 576 | - $('.conversation textarea:visible').focus().val(val + name + ', '); | |
| 577 | - }); | |
| 494 | + // discovering MUC support | |
| 495 | + Jabber.connection.sendIQ( | |
| 496 | + $iq({type: 'get', from: Jabber.connection.jid, to: Jabber.muc_domain}) | |
| 497 | + .c('query', {xmlns: Strophe.NS.DISCO_INFO}), | |
| 498 | + Jabber.on_muc_support | |
| 499 | + ); | |
| 578 | 500 | |
| 579 | - $('#chat .conversation .history').live('click', function() { | |
| 580 | - $('.conversation textarea:visible').focus(); | |
| 581 | - }); | |
| 501 | + // uncomment for extra debugging | |
| 502 | + //Strophe.log = function (lvl, msg) { log(msg); }; | |
| 503 | + }, | |
| 582 | 504 | |
| 583 | - function toggle_chat_window() { | |
| 584 | - if(jQuery('#conversations .conversation').length == 0) jQuery('.buddies a').first().click(); | |
| 585 | - jQuery('#chat').toggleClass('opened'); | |
| 586 | - jQuery('#chat-label').toggleClass('opened'); | |
| 587 | - } | |
| 505 | + connect: function() { | |
| 506 | + if (Notification.permission !== "granted" && Notification.permission !== "denied") { | |
| 507 | + Notification.requestPermission(function (permission) { | |
| 508 | + if (!('permission' in Notification)) { | |
| 509 | + Notification.permission = permission; | |
| 510 | + } | |
| 511 | + }); | |
| 512 | + } | |
| 588 | 513 | |
| 589 | - function load_conversation(jid) { | |
| 590 | - var jid_id = Jabber.jid_to_id(jid); | |
| 591 | - var name = Jabber.name_of(jid_id); | |
| 592 | - if (jid) { | |
| 593 | - if (Strophe.getDomainFromJid(jid) == Jabber.muc_domain) { | |
| 594 | - if (Jabber.muc_supported) { | |
| 595 | - log('opening groupchat with ' + jid); | |
| 596 | - Jabber.jids[jid_id] = {jid: jid, name: name, type: 'groupchat'}; | |
| 597 | - var conversation = create_conversation_tab(name, jid_id); | |
| 598 | - Jabber.enter_room(jid); | |
| 599 | - recent_messages(jid); | |
| 600 | - return conversation; | |
| 601 | - } | |
| 602 | - } | |
| 603 | - else { | |
| 604 | - log('opening chat with ' + jid); | |
| 605 | - Jabber.jids[jid_id] = {jid: jid, name: name, type: 'friendchat'}; | |
| 606 | - var conversation = create_conversation_tab(name, jid_id); | |
| 607 | - recent_messages(jid); | |
| 608 | - return conversation; | |
| 609 | - } | |
| 514 | + if (Jabber.connection && Jabber.connection.connected) { | |
| 515 | + Jabber.send_availability_status(Jabber.presence_status); | |
| 610 | 516 | } |
| 611 | - } | |
| 612 | - | |
| 613 | - function open_conversation(jid) { | |
| 614 | - var conversation = load_conversation(jid); | |
| 615 | - var jid_id = $(this).attr('id'); | |
| 616 | - | |
| 617 | - $('.conversation').hide(); | |
| 618 | - conversation.show(); | |
| 619 | - count_unread_messages(jid_id, true); | |
| 620 | - if(conversation.find('.chat-offset-container-0').length == 0) | |
| 621 | - recent_messages(Jabber.jid_of(jid_id)); | |
| 622 | - conversation.find('.input').focus(); | |
| 623 | - $('#chat').addClass('opened'); | |
| 624 | - $('#chat-label').addClass('opened'); | |
| 625 | - $.post('/chat/tab', {tab_id: jid_id}); | |
| 626 | - } | |
| 627 | - | |
| 628 | - function create_conversation_tab(title, jid_id) { | |
| 629 | - var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 630 | - var conversation = $('#' + conversation_id); | |
| 631 | - if (conversation.length > 0) { | |
| 632 | - return conversation; | |
| 517 | + else { | |
| 518 | + log('starting XMPP/BOSH session...'); | |
| 519 | + $('#buddy-list .toolbar').removeClass('small-loading-dark').addClass('small-loading-dark'); | |
| 520 | + $('.dialog-error').hide(); | |
| 521 | + $.ajax({ | |
| 522 | + url: '/chat/start_session', | |
| 523 | + dataType: 'json', | |
| 524 | + success: function(data) { | |
| 525 | + Jabber.attach_connection(data) | |
| 526 | + }, | |
| 527 | + error: function(error) { | |
| 528 | + $('#buddy-list .toolbar').removeClass('small-loading-dark'); | |
| 529 | + $('#buddy-list .dialog-error') | |
| 530 | + .html(error.responseText) | |
| 531 | + .show('highlight') | |
| 532 | + .unbind('click') | |
| 533 | + .click(function() { $(this).hide('highlight'); }); | |
| 534 | + } | |
| 535 | + }); | |
| 633 | 536 | } |
| 537 | + }, | |
| 634 | 538 | |
| 635 | - var jid = Jabber.jid_of(jid_id); | |
| 636 | - var identifier = getIdentifier(jid); | |
| 539 | + deliver_message: function(jid, body) { | |
| 540 | + var jid_id = Jabber.jid_to_id(jid); | |
| 541 | + var type = Jabber.type_of(jid_id); | |
| 542 | + var presence = Jabber.presence_of(jid_id); | |
| 543 | + var message = $msg({to: jid, from: Jabber.connection.jid, "type": type}) | |
| 544 | + .c('body').t(body).up() | |
| 545 | + .c('active', {xmlns: Strophe.NS.CHAT_STATES}); | |
| 546 | + Jabber.connection.send(message); | |
| 547 | + Jabber.show_message(jid, $own_name, escape_html(body), 'self', Strophe.getNodeFromJid(Jabber.connection.jid)); | |
| 548 | + save_message(jid, body); | |
| 549 | + renew_conversation_order(jid); | |
| 550 | + move_conversation_to_the_top(jid); | |
| 551 | + if (presence == 'offline') | |
| 552 | + Jabber.show_notice(jid_id, $user_unavailable_error); | |
| 553 | + }, | |
| 554 | + | |
| 555 | + is_a_room: function(jid_id) { | |
| 556 | + return Jabber.type_of(jid_id) == 'groupchat'; | |
| 557 | + }, | |
| 558 | + | |
| 559 | + show_notice: function(jid_id, msg) { | |
| 560 | + var tab_id = '#' + Jabber.conversation_prefix + jid_id; | |
| 561 | + var history = $(tab_id).find('.history'); | |
| 562 | + var notice = $(tab_id).find('.history .notice'); | |
| 563 | + if (notice.length > 0) | |
| 564 | + notice.html(msg) | |
| 565 | + else | |
| 566 | + $(tab_id).find('.history').append("<span class='notice'>" + msg + "</span>"); | |
| 567 | + history.scrollTo({top:'100%', left:'0%'}); | |
| 568 | + }, | |
| 569 | + | |
| 570 | + remove_notice: function(jid_id) { | |
| 571 | + var tab_id = '#' + Jabber.conversation_prefix + jid_id; | |
| 572 | + var notice = $(tab_id).find('.history .notice').remove(); | |
| 573 | + }, | |
| 574 | + }; | |
| 637 | 575 | |
| 638 | - var panel = $('#chat-templates .conversation').clone().appendTo($conversations).attr('id', conversation_id); | |
| 639 | - panel.find('.chat-target .avatar').replaceWith(getAvatar(identifier)); | |
| 640 | - panel.find('.chat-target .other-name').html(title); | |
| 641 | - $('#chat .history').perfectScrollbar(); | |
| 576 | + $('#chat-connect').live('click', function() { | |
| 577 | + Jabber.presence_status = 'chat'; | |
| 578 | + Jabber.connect(); | |
| 579 | + $('#chat .simplemenu-submenu').hide(); | |
| 580 | + return false; | |
| 581 | + }); | |
| 642 | 582 | |
| 643 | - panel.find('.history').scroll(function(){ | |
| 644 | - if($(this).scrollTop() == 0){ | |
| 645 | - var offset = panel.find('.message p').size(); | |
| 646 | - recent_messages(jid, offset); | |
| 647 | - } | |
| 648 | - }); | |
| 583 | + $('#chat-disconnect').click(function() { | |
| 584 | + disconnect(); | |
| 585 | + $('#chat .simplemenu-submenu').hide(); | |
| 586 | + return false; | |
| 587 | + }); | |
| 588 | + | |
| 589 | + $('#chat-busy').click(function() { | |
| 590 | + Jabber.presence_status = 'dnd'; | |
| 591 | + Jabber.connect(); | |
| 592 | + $('#chat .simplemenu-submenu').hide(); | |
| 593 | + return false; | |
| 594 | + }); | |
| 649 | 595 | |
| 650 | - var textarea = panel.find('textarea'); | |
| 651 | - textarea.attr('name', panel.id); | |
| 596 | + $('#chat-retry').live('click', function() { | |
| 597 | + Jabber.presence_status = Jabber.presence_status || 'chat'; | |
| 598 | + Jabber.connect(); | |
| 599 | + return false; | |
| 600 | + }); | |
| 601 | + | |
| 602 | + $('.conversation textarea').live('keydown', function(e) { | |
| 603 | + if (e.keyCode == 13) { | |
| 604 | + var jid = $(this).attr('data-to'); | |
| 605 | + var body = $(this).val(); | |
| 606 | + body = $('<div>'+ body +'</div>').find('script,noscript,style').remove().end().html(); | |
| 607 | + Jabber.deliver_message(jid, body); | |
| 608 | + $(this).val(''); | |
| 609 | + return false; | |
| 610 | + } | |
| 611 | + }); | |
| 652 | 612 | |
| 653 | - if (Jabber.is_a_room(jid_id)) { | |
| 654 | - panel.append(Jabber.template('.occupant-list-template')); | |
| 655 | - panel.find('.history').addClass('room'); | |
| 656 | - var room_actions = $('#chat-templates .room-action').clone(); | |
| 657 | - room_actions.data('jid', jid); | |
| 658 | - panel.find('.history').after(room_actions); | |
| 659 | - $('#chat .occupants .occupant-list').perfectScrollbar(); | |
| 613 | + function save_message(jid, body) { | |
| 614 | + $.post('/chat/save_message', { | |
| 615 | + to: getIdentifier(jid), | |
| 616 | + body: body | |
| 617 | + }, function(data){ | |
| 618 | + if(data.status > 0){ | |
| 619 | + console.log(data.message); | |
| 620 | + if(data.backtrace) console.log(data.backtrace); | |
| 660 | 621 | } |
| 661 | - textarea.attr('data-to', jid); | |
| 662 | - | |
| 663 | - return panel; | |
| 664 | - } | |
| 665 | - | |
| 666 | - function ensure_scroll(jid, offset) { | |
| 667 | - var jid_id = Jabber.jid_to_id(jid); | |
| 668 | - var history = jQuery('#conversation-'+jid_id+' .history'); | |
| 669 | - // Load more messages if was not enough to show the scroll | |
| 670 | - if(history.prop('scrollHeight') - history.prop('clientHeight') <= 0){ | |
| 671 | - var offset = history.find('.message p').size(); | |
| 672 | - recent_messages(jid, offset); | |
| 673 | - } | |
| 674 | - } | |
| 675 | - | |
| 676 | - function recent_messages(jid, offset) { | |
| 677 | - if (Jabber.no_more_messages[jid]) return; | |
| 678 | - | |
| 679 | - if(!offset) offset = 0; | |
| 680 | - start_fetching('.history'); | |
| 681 | - $.getJSON('/chat/recent_messages', {identifier: getIdentifier(jid), offset: offset}, function(data) { | |
| 682 | - // Register if no more messages returned and stop trying to load | |
| 683 | - // more messages in the future. | |
| 684 | - if(data.length == 0) | |
| 685 | - Jabber.no_more_messages[jid] = true; | |
| 686 | - | |
| 687 | - $.each(data, function(i, message) { | |
| 688 | - var body = message['body']; | |
| 689 | - var from = message['from']; | |
| 690 | - var to = message['to']; | |
| 691 | - var date = message['created_at']; | |
| 692 | - var who = from['id']==getCurrentIdentifier() ? 'self' : from['id'] | |
| 693 | - | |
| 694 | - Jabber.show_message(jid, from['name'], body, who, from['id'], date, offset); | |
| 695 | - }); | |
| 696 | - stop_fetching('.history'); | |
| 697 | - ensure_scroll(jid, offset); | |
| 698 | - }); | |
| 699 | - } | |
| 700 | - | |
| 701 | - function move_conversation_to_the_top(jid) { | |
| 702 | - id = Jabber.jid_to_id(jid); | |
| 703 | - var link = $('#'+id); | |
| 704 | - var li = link.closest('li'); | |
| 705 | - var ul = link.closest('ul'); | |
| 706 | - ul.prepend(li); | |
| 707 | - } | |
| 708 | - | |
| 709 | - function sort_conversations() { | |
| 710 | - $.getJSON('/chat/recent_conversations', {}, function(data) { | |
| 711 | - $.each(data['order'], function(i, identifier) { | |
| 712 | - move_conversation_to_the_top(identifier+'-'+data['domain']); | |
| 713 | - }) | |
| 714 | - }) | |
| 715 | - } | |
| 716 | - | |
| 717 | - function load_defaults() { | |
| 718 | - $.getJSON('/chat/my_session', {}, function(data) { | |
| 719 | - $.each(data.rooms, function(i, room_jid) { | |
| 720 | - $('#chat').trigger('opengroup', room_jid); | |
| 721 | - }) | |
| 722 | - | |
| 723 | - $('#'+data.tab_id).click(); | |
| 724 | - | |
| 725 | - if(data.status == 'opened') | |
| 726 | - toggle_chat_window(); | |
| 727 | - }) | |
| 728 | - } | |
| 729 | - | |
| 730 | - function count_unread_messages(jid_id, hide) { | |
| 731 | - var unread = $('.buddies #'+jid_id+ ' .unread-messages'); | |
| 732 | - if (hide) { | |
| 733 | - unread.hide(); | |
| 734 | - unread.siblings('img').show(); | |
| 735 | - Jabber.unread_messages_of(jid_id, 0); | |
| 736 | - unread.text(''); | |
| 622 | + }).fail(function(){ | |
| 623 | + console.log('500 - Internal server error.') | |
| 624 | + }); | |
| 625 | + } | |
| 626 | + | |
| 627 | + // open new conversation or change to already opened tab | |
| 628 | + $('#buddy-list .buddies li a').live('click', function() { | |
| 629 | + var jid = Jabber.jid_of($(this).attr('id')); | |
| 630 | + open_conversation(jid); | |
| 631 | + return false; | |
| 632 | + }); | |
| 633 | + | |
| 634 | + // put name into text area when click in one occupant | |
| 635 | + $('.occupants .occupant-list li a').live('click', function() { | |
| 636 | + var jid_id = $(this).attr('data-id'); | |
| 637 | + var name = Jabber.name_of(jid_id); | |
| 638 | + var val = $('.conversation textarea:visible').val(); | |
| 639 | + $('.conversation textarea:visible').focus().val(val + name + ', '); | |
| 640 | + return false; | |
| 641 | + }); | |
| 642 | + | |
| 643 | + $('#chat .conversation .history').live('click', function() { | |
| 644 | + $('.conversation textarea:visible').focus(); | |
| 645 | + }); | |
| 646 | + | |
| 647 | + function toggle_chat_window() { | |
| 648 | + if(jQuery('#conversations .conversation').length == 0) jQuery('.buddies a').first().click(); | |
| 649 | + jQuery('#chat').toggleClass('opened'); | |
| 650 | + jQuery('#chat-label').toggleClass('opened'); | |
| 651 | + } | |
| 652 | + | |
| 653 | + function load_conversation(jid) { | |
| 654 | + var jid_id = Jabber.jid_to_id(jid); | |
| 655 | + var name = Jabber.name_of(jid_id); | |
| 656 | + if (jid) { | |
| 657 | + if (Strophe.getDomainFromJid(jid) == Jabber.muc_domain) { | |
| 658 | + if (Jabber.muc_supported) { | |
| 659 | + log('opening groupchat with ' + jid); | |
| 660 | + Jabber.jids[jid_id] = {jid: jid, name: name, type: 'groupchat'}; | |
| 661 | + var conversation = create_conversation_tab(name, jid_id); | |
| 662 | + Jabber.enter_room(jid); | |
| 663 | + recent_messages(jid, 0, true); | |
| 664 | + return conversation; | |
| 665 | + } | |
| 737 | 666 | } |
| 738 | 667 | else { |
| 739 | - unread.siblings('img').hide(); | |
| 740 | - unread.css('display', 'inline-block'); | |
| 741 | - var unread_messages = Jabber.unread_messages_of(jid_id) || 0; | |
| 742 | - Jabber.unread_messages_of(jid_id, ++unread_messages); | |
| 743 | - unread.text(unread_messages); | |
| 744 | - } | |
| 745 | - update_total_unread_messages(); | |
| 746 | - } | |
| 747 | - | |
| 748 | - function update_total_unread_messages() { | |
| 749 | - var total_unread = $('#openchat .unread-messages'); | |
| 750 | - var sum = 0; | |
| 751 | - $('.buddies .unread-messages').each(function() { | |
| 752 | - sum += Number($(this).text()); | |
| 753 | - }); | |
| 754 | - if(sum>0) { | |
| 755 | - total_unread.text(sum); | |
| 756 | - } else { | |
| 757 | - total_unread.text(''); | |
| 668 | + log('opening chat with ' + jid); | |
| 669 | + Jabber.jids[jid_id] = {jid: jid, name: name, type: 'chat'}; | |
| 670 | + var conversation = create_conversation_tab(name, jid_id); | |
| 671 | + recent_messages(jid, 0, true); | |
| 672 | + return conversation; | |
| 758 | 673 | } |
| 759 | - } | |
| 674 | + } | |
| 675 | + } | |
| 676 | + | |
| 677 | + function open_conversation(jid) { | |
| 678 | + var conversation = load_conversation(jid); | |
| 679 | + var jid_id = Jabber.jid_to_id(jid); | |
| 680 | + | |
| 681 | + $('.conversation').hide(); | |
| 682 | + conversation.show(); | |
| 683 | + conversation.find('.input').focus(); | |
| 684 | + $('#chat').addClass('opened'); | |
| 685 | + $('#chat-label').addClass('opened'); | |
| 686 | + $.post('/chat/tab', {tab_id: jid_id}); | |
| 687 | + } | |
| 688 | + | |
| 689 | + function create_conversation_tab(title, jid_id) { | |
| 690 | + var conversation_id = Jabber.conversation_prefix + jid_id; | |
| 691 | + var conversation = $('#' + conversation_id); | |
| 692 | + if (conversation.length > 0) { | |
| 693 | + return conversation; | |
| 694 | + } | |
| 695 | + | |
| 696 | + var jid = Jabber.jid_of(jid_id); | |
| 697 | + var identifier = getIdentifier(jid); | |
| 760 | 698 | |
| 761 | - var $conversations = $('#chat-window #conversations'); | |
| 699 | + var panel = $('#chat-templates .conversation').clone().appendTo($conversations).attr('id', conversation_id); | |
| 700 | + panel.find('.chat-target .avatar').replaceWith(getAvatar(identifier)); | |
| 701 | + panel.find('.chat-target .other-name').html(title); | |
| 702 | + $('#chat .history').perfectScrollbar(); | |
| 762 | 703 | |
| 763 | - function log(msg) { | |
| 764 | - if(Jabber.debug && window.console && window.console.log) { | |
| 765 | - var time = new Date(); | |
| 766 | - window.console.log('['+ time.toTimeString() +'] ' + msg); | |
| 704 | + panel.find('.history').scroll(function(){ | |
| 705 | + if($(this).scrollTop() == 0){ | |
| 706 | + var offset = panel.find('.message p').size(); | |
| 707 | + recent_messages(jid, offset); | |
| 767 | 708 | } |
| 768 | - } | |
| 709 | + }); | |
| 710 | + | |
| 711 | + var textarea = panel.find('textarea'); | |
| 712 | + textarea.attr('name', panel.id); | |
| 713 | + | |
| 714 | + if (Jabber.is_a_room(jid_id)) { | |
| 715 | + panel.append(Jabber.template('.occupant-list-template')); | |
| 716 | + panel.find('.history').addClass('room'); | |
| 717 | + var room_actions = $('#chat-templates .room-action').clone(); | |
| 718 | + room_actions.data('jid', jid); | |
| 719 | + panel.find('.history').after(room_actions); | |
| 720 | + $('#chat .occupants .occupant-list').perfectScrollbar(); | |
| 721 | + } | |
| 722 | + textarea.attr('data-to', jid); | |
| 723 | + | |
| 724 | + return panel; | |
| 725 | + } | |
| 726 | + | |
| 727 | + function ensure_scroll(jid, offset) { | |
| 728 | + var jid_id = Jabber.jid_to_id(jid); | |
| 729 | + var history = jQuery('#conversation-'+jid_id+' .history'); | |
| 730 | + // Load more messages if was not enough to show the scroll | |
| 731 | + if(history.prop('scrollHeight') - history.prop('clientHeight') <= 0){ | |
| 732 | + var offset = history.find('.message p').size(); | |
| 733 | + recent_messages(jid, offset); | |
| 734 | + } | |
| 735 | + } | |
| 736 | + | |
| 737 | + function recent_messages(jid, offset, clear_unread) { | |
| 738 | + if (Jabber.no_more_messages[jid]) return; | |
| 739 | + | |
| 740 | + if(!offset) offset = 0; | |
| 741 | + start_fetching('.history'); | |
| 742 | + $.getJSON('/chat/recent_messages', {identifier: getIdentifier(jid), offset: offset}, function(data) { | |
| 743 | + // Register if no more messages returned and stop trying to load | |
| 744 | + // more messages in the future. | |
| 745 | + if(data.length == 0) | |
| 746 | + Jabber.no_more_messages[jid] = true; | |
| 747 | + | |
| 748 | + $.each(data, function(i, message) { | |
| 749 | + var body = message['body']; | |
| 750 | + var from = message['from']; | |
| 751 | + var to = message['to']; | |
| 752 | + var date = message['created_at']; | |
| 753 | + var who = from['id']==getCurrentIdentifier() ? 'self' : from['id'] | |
| 754 | + | |
| 755 | + Jabber.show_message(jid, from['name'], body, who, from['id'], date, offset); | |
| 756 | + }); | |
| 757 | + stop_fetching('.history'); | |
| 758 | + ensure_scroll(jid, offset); | |
| 769 | 759 | |
| 770 | - function escape_html(body) { | |
| 771 | - return body | |
| 772 | - .replace(/&/g, '&') | |
| 773 | - .replace(/</g, '<') | |
| 774 | - .replace(/>/g, '>'); | |
| 775 | - } | |
| 760 | + if(clear_unread){ | |
| 761 | + var jid_id = Jabber.jid_to_id(jid); | |
| 762 | + count_unread_messages(jid_id, true); | |
| 763 | + } | |
| 764 | + }); | |
| 765 | + } | |
| 766 | + | |
| 767 | + function move_conversation_to_the_top(jid) { | |
| 768 | + id = Jabber.jid_to_id(jid); | |
| 769 | + var link = $('#'+id); | |
| 770 | + var li = link.closest('li'); | |
| 771 | + var ul = link.closest('ul'); | |
| 772 | + ul.prepend(li); | |
| 773 | + } | |
| 774 | + | |
| 775 | + function renew_conversation_order(jid){ | |
| 776 | + var i = Jabber.conversations_order.indexOf(jid); | |
| 777 | + // Remove element from the list | |
| 778 | + if(i >= 0) { | |
| 779 | + var elem = Jabber.conversations_order[i]; | |
| 780 | + var a = Jabber.conversations_order.slice(0,i); | |
| 781 | + var b = Jabber.conversations_order.slice(i+1, Jabber.conversations_order.length); | |
| 782 | + Jabber.conversations_order = a.concat(b); | |
| 783 | + } else | |
| 784 | + var elem = jid; | |
| 785 | + | |
| 786 | + Jabber.conversations_order = Jabber.conversations_order.concat(elem); | |
| 787 | + } | |
| 788 | + | |
| 789 | + function sort_conversations() { | |
| 790 | + if(Jabber.conversations_order){ | |
| 791 | + for (var i = 0; i < Jabber.conversations_order.length; i++) | |
| 792 | + move_conversation_to_the_top(Jabber.conversations_order[i]); | |
| 793 | + } | |
| 794 | + } | |
| 795 | + | |
| 796 | + function load_defaults() { | |
| 797 | + $.getJSON('/chat/my_session', {}, function(data) { | |
| 798 | + $.each(data.rooms, function(i, room_jid) { | |
| 799 | + load_conversation(room_jid); | |
| 800 | + }) | |
| 801 | + | |
| 802 | + $('#'+data.tab_id).click(); | |
| 803 | + | |
| 804 | + if(data.status == 'opened') | |
| 805 | + toggle_chat_window(); | |
| 806 | + }) | |
| 807 | + } | |
| 808 | + | |
| 809 | + function count_unread_messages(jid_id, hide) { | |
| 810 | + var unread = $('.buddies #'+jid_id+ ' .unread-messages'); | |
| 811 | + if (hide) { | |
| 812 | + unread.hide(); | |
| 813 | + unread.siblings('img').show(); | |
| 814 | + Jabber.unread_messages_of(jid_id, 0); | |
| 815 | + unread.text(''); | |
| 816 | + } | |
| 817 | + else { | |
| 818 | + unread.siblings('img').hide(); | |
| 819 | + unread.css('display', 'inline-block'); | |
| 820 | + var unread_messages = Jabber.unread_messages_of(jid_id) || 0; | |
| 821 | + Jabber.unread_messages_of(jid_id, ++unread_messages); | |
| 822 | + unread.text(unread_messages); | |
| 823 | + } | |
| 824 | + update_total_unread_messages(); | |
| 825 | + } | |
| 826 | + | |
| 827 | + function update_total_unread_messages() { | |
| 828 | + var total_unread = $('#unread-messages'); | |
| 829 | + var sum = 0; | |
| 830 | + $('#chat .unread-messages').each(function() { | |
| 831 | + sum += Number($(this).text()); | |
| 832 | + }); | |
| 833 | + if(sum>0) { | |
| 834 | + total_unread.text(sum); | |
| 835 | + } else { | |
| 836 | + total_unread.text(''); | |
| 837 | + } | |
| 838 | + } | |
| 776 | 839 | |
| 777 | - function getCurrentIdentifier() { | |
| 778 | - return getIdentifier(Jabber.connection.jid); | |
| 779 | - } | |
| 840 | + var $conversations = $('#chat-window #conversations'); | |
| 780 | 841 | |
| 781 | - function getIdentifier(jid) { | |
| 782 | - return Strophe.getNodeFromJid(jid); | |
| 783 | - } | |
| 842 | + function log(msg) { | |
| 843 | + if(Jabber.debug && window.console && window.console.log) { | |
| 844 | + var time = new Date(); | |
| 845 | + window.console.log('['+ time.toTimeString() +'] ' + msg); | |
| 846 | + } | |
| 847 | + } | |
| 848 | + | |
| 849 | + function escape_html(body) { | |
| 850 | + return body | |
| 851 | + .replace(/&/g, '&') | |
| 852 | + .replace(/</g, '<') | |
| 853 | + .replace(/>/g, '>'); | |
| 854 | + } | |
| 855 | + | |
| 856 | + function getCurrentIdentifier() { | |
| 857 | + return getIdentifier(Jabber.connection.jid); | |
| 858 | + } | |
| 859 | + | |
| 860 | + function getIdentifier(jid) { | |
| 861 | + return Strophe.getNodeFromJid(jid); | |
| 862 | + } | |
| 863 | + | |
| 864 | + function getMyAvatar() { | |
| 865 | + return getAvatar(getCurrentIdentifier()); | |
| 866 | + } | |
| 867 | + | |
| 868 | + function getAvatar(identifier) { | |
| 869 | + if(Jabber.avatars[identifier]) | |
| 870 | + var src = Jabber.avatars[identifier]; | |
| 871 | + else | |
| 872 | + var src = "/chat/avatar/"+identifier; | |
| 873 | + | |
| 874 | + return '<img class="avatar" src="' + src + '">'; | |
| 875 | + } | |
| 876 | + | |
| 877 | + function disconnect() { | |
| 878 | + log('disconnect'); | |
| 879 | + if (Jabber.connection && Jabber.connection.connected) { | |
| 880 | + Jabber.connection.disconnect(); | |
| 881 | + } | |
| 882 | + Jabber.presence_status = 'offline'; | |
| 883 | + Jabber.show_status('offline'); | |
| 884 | + } | |
| 885 | + | |
| 886 | + function notifyMessage(message) { | |
| 887 | + var jid = Strophe.getBareJidFromJid(message.from); | |
| 888 | + var jid_id = Jabber.jid_to_id(jid); | |
| 889 | + var name = Jabber.name_of(jid_id); | |
| 890 | + var identifier = Strophe.getNodeFromJid(jid); | |
| 891 | + var avatar = "/chat/avatar/"+identifier | |
| 892 | + if(!$('#chat').hasClass('opened') || window.isHidden() || !Jabber.window_visibility) { | |
| 893 | + var options = {body: message.body, icon: avatar, tag: jid_id}; | |
| 894 | + $(notifyMe(name, options)).on('click', function(){ | |
| 895 | + open_conversation(jid); | |
| 896 | + }); | |
| 897 | + Jabber.notification_sound.play(); | |
| 898 | + } | |
| 899 | + } | |
| 784 | 900 | |
| 785 | - function getMyAvatar() { | |
| 786 | - return getAvatar(getCurrentIdentifier()); | |
| 787 | - } | |
| 901 | + $('.title-bar a').click(function() { | |
| 902 | + $(this).parents('.status-group').find('.buddies').toggle('fast'); | |
| 903 | + return false; | |
| 904 | + }); | |
| 905 | + $('#chat').on('click', '.occupants a', function() { | |
| 906 | + $(this).siblings('.occupant-list').toggle('fast'); | |
| 907 | + $(this).toggleClass('up'); | |
| 908 | + return false; | |
| 909 | + }); | |
| 788 | 910 | |
| 789 | - function getAvatar(identifier) { | |
| 790 | - return '<img class="avatar" src="/chat/avatar/' + identifier + '">'; | |
| 791 | - } | |
| 911 | + //restore connection if user was connected | |
| 912 | + if($presence=='' || $presence == 'chat') { | |
| 913 | + $('#chat-connect').trigger('click'); | |
| 914 | + } else if($presence == 'dnd') { | |
| 915 | + $('#chat-busy').trigger('click'); | |
| 916 | + } | |
| 792 | 917 | |
| 793 | - function disconnect() { | |
| 794 | - log('disconnect'); | |
| 795 | - if (Jabber.connection && Jabber.connection.connected) { | |
| 796 | - Jabber.connection.disconnect(); | |
| 797 | - } | |
| 798 | - Jabber.presence_status = 'offline'; | |
| 799 | - Jabber.show_status('offline'); | |
| 800 | - } | |
| 801 | - | |
| 802 | - function notifyMessage(message) { | |
| 803 | - var jid = Strophe.getBareJidFromJid(message.from); | |
| 804 | - var jid_id = Jabber.jid_to_id(jid); | |
| 805 | - var name = Jabber.name_of(jid_id); | |
| 806 | - var identifier = Strophe.getNodeFromJid(jid); | |
| 807 | - var avatar = "/chat/avatar/"+identifier | |
| 808 | - if(!$('#chat').hasClass('opened') || window.isHidden()) { | |
| 809 | - var options = {body: message.body, icon: avatar, tag: jid_id}; | |
| 810 | - console.log('Notify '+name); | |
| 811 | - $(notifyMe(name, options)).on('click', function(){ | |
| 812 | - open_conversation(jid); | |
| 813 | - }); | |
| 814 | - $.sound.play('/sounds/receive.wav'); | |
| 815 | - } | |
| 816 | - } | |
| 817 | - | |
| 818 | - $('.title-bar a').click(function() { | |
| 819 | - $(this).parents('.status-group').find('.buddies').toggle('fast'); | |
| 820 | - }); | |
| 821 | - $('#chat').on('click', '.occupants a', function() { | |
| 822 | - $(this).siblings('.occupant-list').toggle('fast'); | |
| 823 | - $(this).toggleClass('up'); | |
| 824 | - }); | |
| 825 | - | |
| 826 | - //restore connection if user was connected | |
| 827 | - if($presence=='' || $presence == 'chat') { | |
| 828 | - $('#chat-connect').trigger('click'); | |
| 829 | - } else if($presence == 'dnd') { | |
| 830 | - $('#chat-busy').trigger('click'); | |
| 831 | - } | |
| 832 | - | |
| 833 | - $('#chat #buddy-list .buddies').perfectScrollbar(); | |
| 918 | + $('#chat #buddy-list .buddies').perfectScrollbar(); | |
| 834 | 919 | |
| 835 | 920 | // custom css expression for a case-insensitive contains() |
| 836 | 921 | jQuery.expr[':'].Contains = function(a,i,m){ |
| 837 | - return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0; | |
| 922 | + return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0; | |
| 838 | 923 | }; |
| 839 | 924 | |
| 840 | 925 | $('#chat .search').change( function () { |
| ... | ... | @@ -856,6 +941,7 @@ jQuery(function($) { |
| 856 | 941 | |
| 857 | 942 | $('#chat .buddies a').live('click', function(){ |
| 858 | 943 | $('#chat .search').val('').change(); |
| 944 | + return false; | |
| 859 | 945 | }); |
| 860 | 946 | |
| 861 | 947 | $('#chat-label').click(function(){ |
| ... | ... | @@ -871,6 +957,14 @@ jQuery(function($) { |
| 871 | 957 | $('.room-action.leave').live('click', function(){ |
| 872 | 958 | var jid = $(this).data('jid'); |
| 873 | 959 | Jabber.leave_room(jid); |
| 960 | + return false; | |
| 961 | + }); | |
| 962 | + | |
| 963 | + $('.open-conversation').live('click', function(){ | |
| 964 | + open_conversation($(this).data('jid')); | |
| 965 | + return false; | |
| 874 | 966 | }); |
| 875 | 967 | |
| 968 | + window.onfocus = function() {Jabber.window_visibility = true}; | |
| 969 | + window.onblur = function() {Jabber.window_visibility = false}; | |
| 876 | 970 | }); | ... | ... |
public/stylesheets/chat.css
| ... | ... | @@ -201,6 +201,21 @@ |
| 201 | 201 | bottom: 132px; |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | +#chat-label.opened #unread-messages, | |
| 205 | +#unread-messages:empty { | |
| 206 | + display: none; | |
| 207 | +} | |
| 208 | + | |
| 209 | +#unread-messages { | |
| 210 | + padding: 3px 5px; | |
| 211 | + background-color: #F57900; | |
| 212 | + border-radius: 5px; | |
| 213 | + margin-top: -10px; | |
| 214 | + margin-left: -30px; | |
| 215 | + position: absolute; | |
| 216 | + z-index: 1; | |
| 217 | +} | |
| 218 | + | |
| 204 | 219 | #chat .unread-messages { |
| 205 | 220 | height: 32px; |
| 206 | 221 | line-height: 32px; | ... | ... |
test/functional/chat_controller_test.rb
| ... | ... | @@ -95,6 +95,54 @@ class ChatControllerTest < ActionController::TestCase |
| 95 | 95 | assert_not_equal chat_status_at, @person.user.chat_status_at |
| 96 | 96 | end |
| 97 | 97 | |
| 98 | + should 'forbid to register a message without to' do | |
| 99 | + @controller.stubs(:current_user).returns(@person.user) | |
| 100 | + @request.stubs(:xhr?).returns(true) | |
| 101 | + | |
| 102 | + post :save_message, {:body =>'Hello!'} | |
| 103 | + assert ActiveSupport::JSON.decode(@response.body)['status'] == 1 | |
| 104 | + end | |
| 105 | + | |
| 106 | + should 'forbid to register a message without body' do | |
| 107 | + @controller.stubs(:current_user).returns(@person.user) | |
| 108 | + @request.stubs(:xhr?).returns(true) | |
| 109 | + | |
| 110 | + post :save_message, {:to =>'mary'} | |
| 111 | + assert ActiveSupport::JSON.decode(@response.body)['status'] == 1 | |
| 112 | + end | |
| 113 | + | |
| 114 | + should 'forbid user to register a message to a stranger' do | |
| 115 | + @controller.stubs(:current_user).returns(@person.user) | |
| 116 | + @request.stubs(:xhr?).returns(true) | |
| 117 | + | |
| 118 | + post :save_message, {:to =>'random', :body => 'Hello, stranger!'} | |
| 119 | + assert ActiveSupport::JSON.decode(@response.body)['status'] == 2 | |
| 120 | + end | |
| 121 | + | |
| 122 | + should 'register a message to a friend' do | |
| 123 | + @controller.stubs(:current_user).returns(@person.user) | |
| 124 | + friend = create_user('friend').person | |
| 125 | + @person.add_friend friend | |
| 126 | + @request.stubs(:xhr?).returns(true) | |
| 127 | + | |
| 128 | + assert_difference 'ChatMessage.count', 1 do | |
| 129 | + post :save_message, {:to => friend.identifier, :body => 'Hey! How is it going?'} | |
| 130 | + assert ActiveSupport::JSON.decode(@response.body)['status'] == 0 | |
| 131 | + end | |
| 132 | + end | |
| 133 | + | |
| 134 | + should 'register a message to a group' do | |
| 135 | + @controller.stubs(:current_user).returns(@person.user) | |
| 136 | + group = fast_create(Organization) | |
| 137 | + group.add_member(@person) | |
| 138 | + @request.stubs(:xhr?).returns(true) | |
| 139 | + | |
| 140 | + assert_difference 'ChatMessage.count', 1 do | |
| 141 | + post :save_message, {:to => group.identifier, :body => 'Hey! How is it going?'} | |
| 142 | + assert ActiveSupport::JSON.decode(@response.body)['status'] == 0 | |
| 143 | + end | |
| 144 | + end | |
| 145 | + | |
| 98 | 146 | should 'toggle chat status' do |
| 99 | 147 | login_as 'testuser' |
| 100 | 148 | ... | ... |
| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class ChatMessageTest < ActiveSupport::TestCase | |
| 4 | + should 'create message' do | |
| 5 | + assert_difference 'ChatMessage.count', 1 do | |
| 6 | + ChatMessage.create!(:from => fast_create(Person), :to => fast_create(Person), :body => 'Hey! How are you?' ) | |
| 7 | + end | |
| 8 | + end | |
| 9 | +end | ... | ... |