| ... | ... |
@@ -1,4 +1,7 @@ |
| 1 | 1 |
this.App = |
| 2 |
+ debug: (msg) -> |
|
| 3 |
+ console.log msg |
|
| 4 |
+ |
|
| 2 | 5 |
UI: |
| 3 | 6 |
setAutoHeight: -> |
| 4 | 7 |
height = $(window).height() |
| ... | ... |
@@ -10,24 +13,42 @@ this.App = |
| 10 | 10 |
App._dispatcher = new WebSocketRails('www.xmpp.dev:3000/websocket')
|
| 11 | 11 |
App._dispatcher.on_open = => |
| 12 | 12 |
@_setupBackboneComponents() |
| 13 |
+ @_bindEvents() |
|
| 13 | 14 |
callback?() |
| 14 | 15 |
|
| 15 | 16 |
fetch: (options) -> |
| 16 | 17 |
_.defaults(options, {data: {} })
|
| 17 | 18 |
App._dispatcher.trigger(options.event, options.data, options.success, options.error) |
| 18 | 19 |
|
| 19 |
- getRoster: -> |
|
| 20 |
- App.Com.fetch({
|
|
| 21 |
- event: 'app.roster.contacts' |
|
| 22 |
- success: (data, contacts = data.contacts) -> |
|
| 23 |
- _.each(contacts, (contact) -> |
|
| 24 |
- newContact = new Xmpp.Models.Contact(contact) |
|
| 20 |
+ initRoster: -> |
|
| 21 |
+ App.Com.fetch( |
|
| 22 |
+ event: 'app.roster.initRoster' |
|
| 23 |
+ success: (data) -> |
|
| 24 |
+ _.each(data.contacts, (jid) -> |
|
| 25 |
+ newContact = new Xmpp.Models.Contact(id: jid, jid: jid) |
|
| 25 | 26 |
App.Collections.Contacts.add newContact |
| 26 | 27 |
) |
| 27 |
- }) |
|
| 28 |
+ ) |
|
| 29 |
+ |
|
| 30 |
+ startFetchingVcards: -> |
|
| 31 |
+ App.Com.fetch(event: 'app.roster.startFetchingVcards') |
|
| 32 |
+ |
|
| 33 |
+ startPollingRoster: -> |
|
| 34 |
+ App.Com.fetch(event: 'app.roster.startPolling') |
|
| 28 | 35 |
|
| 29 | 36 |
_setupBackboneComponents: -> |
| 30 | 37 |
App.Collections.Contacts = new Xmpp.Collections.ContactsCollection() |
| 31 | 38 |
|
| 39 |
+ _bindEvents: -> |
|
| 40 |
+ App._dispatcher.bind('app.roster.statusChanged', (result) ->
|
|
| 41 |
+ App.debug 'change contact state' |
|
| 42 |
+ App.Collections.Contacts.updateStatus(result) |
|
| 43 |
+ ) |
|
| 44 |
+ |
|
| 45 |
+ App._dispatcher.bind('app.roster.vcard', (result) ->
|
|
| 46 |
+ App.debug 'got vcard' |
|
| 47 |
+ App.Collections.Contacts.udpateVcard(result) |
|
| 48 |
+ ) |
|
| 49 |
+ |
|
| 32 | 50 |
Collections: |
| 33 | 51 |
Contacts: null |
| ... | ... |
@@ -2,12 +2,18 @@ class Xmpp.Models.Contact extends Xmpp.Models.Model |
| 2 | 2 |
namespace: 'app.roster' |
| 3 | 3 |
|
| 4 | 4 |
defaults: |
| 5 |
- status: '' |
|
| 6 |
- state: 'online' |
|
| 5 |
+ jid: '' |
|
| 6 |
+ name: '' |
|
| 7 |
+ status: 'offline' |
|
| 8 |
+ message: '' |
|
| 7 | 9 |
|
| 8 | 10 |
initialize: -> |
| 9 | 11 |
_.bindAll(this) |
| 10 | 12 |
|
| 13 |
+ if ! @get('name')
|
|
| 14 |
+ @set(name: @get('jid'))
|
|
| 15 |
+ |
|
| 16 |
+ |
|
| 11 | 17 |
class Xmpp.Collections.ContactsCollection extends Backbone.Collection |
| 12 | 18 |
model: Xmpp.Models.Contact |
| 13 | 19 |
|
| ... | ... |
@@ -21,4 +27,10 @@ class Xmpp.Collections.ContactsCollection extends Backbone.Collection |
| 21 | 21 |
|
| 22 | 22 |
appendContact: (contact) -> |
| 23 | 23 |
@counter++ |
| 24 |
- @friendsList.appendContact(contact) |
|
| 25 | 24 |
\ No newline at end of file |
| 25 |
+ @friendsList.appendContact(contact) |
|
| 26 |
+ |
|
| 27 |
+ updateStatus: (response) -> |
|
| 28 |
+ @get(response.jid).set(message: response.status.message, status: response.status.status) |
|
| 29 |
+ |
|
| 30 |
+ udpateVcard: (response) -> |
|
| 31 |
+ @get(response.jid).set(name: response.vcard.name) |
|
| 26 | 32 |
\ No newline at end of file |
| ... | ... |
@@ -1,15 +1,13 @@ |
| 1 |
-%li.clear.user |
|
| 2 |
- .avatar |
|
| 3 |
- %img{src: 'assets/avatar.png', alt: ("t chat.roster.avatar_alt") }
|
|
| 4 |
- %h1 |
|
| 5 |
- #{@jid}
|
|
| 6 |
- -#{@state}
|
|
| 7 |
- %span.status.icon-record{class: "#{@state}"}
|
|
| 8 |
- %h2 #{@jid}
|
|
| 9 |
- -#%span.action |
|
| 10 |
- %span.icon-bubbles |
|
| 11 |
- %span invite |
|
| 12 |
--#%li.clear.user |
|
| 1 |
+.avatar |
|
| 2 |
+ %img{src: 'assets/avatar.png', alt: ("t chat.roster.avatar_alt") }
|
|
| 3 |
+%h1 |
|
| 4 |
+ #{@name}
|
|
| 5 |
+ %span.status.icon-record{class: "#{@status}"}
|
|
| 6 |
+%h2 #{@message}
|
|
| 7 |
+%span.action |
|
| 8 |
+ -#%span.icon-bubbles |
|
| 9 |
+ %span invite |
|
| 10 |
+ |
|
| 13 | 11 |
-# .avatar |
| 14 | 12 |
-# %img{src: 'assets/avatar.png', alt: t("chat.avatar_alt")}
|
| 15 | 13 |
-# %h1 |
| ... | ... |
@@ -2,6 +2,8 @@ Xmpp.Views.Contacts ||= {}
|
| 2 | 2 |
|
| 3 | 3 |
class Xmpp.Views.Contacts.ContactView extends Backbone.View |
| 4 | 4 |
template: JST["backbone/templates/contacts/contact"] |
| 5 |
+ tagName: 'li' |
|
| 6 |
+ className: 'clear user' |
|
| 5 | 7 |
|
| 6 | 8 |
# events: |
| 7 | 9 |
# 'click li.user': 'something' |
| ... | ... |
@@ -9,10 +11,16 @@ class Xmpp.Views.Contacts.ContactView extends Backbone.View |
| 9 | 9 |
initialize: () -> |
| 10 | 10 |
_.bindAll(this) |
| 11 | 11 |
|
| 12 |
- @el = '#' + @attributes['listView'].attributes['id'] + ' ul' |
|
| 12 |
+ # Patrim nejakemu zoznamu |
|
| 13 |
+ @parentList = @attributes['listView'] |
|
| 13 | 14 |
|
| 15 |
+ @model.on('change', @updateContact, this)
|
|
| 16 |
+ |
|
| 17 |
+ updateContact: (contact) -> |
|
| 18 |
+ @model = contact |
|
| 14 | 19 |
@render() |
| 15 | 20 |
|
| 16 | 21 |
render: -> |
| 17 | 22 |
contact = @model.toJSON() |
| 18 |
- $(@el).append(@template(contact)) |
|
| 23 |
+ $(@el).html(@template(contact)) |
|
| 24 |
+ return this |
|
| 19 | 25 |
\ No newline at end of file |
| ... | ... |
@@ -9,18 +9,24 @@ class Xmpp.Views.Contacts.ListView extends Backbone.View |
| 9 | 9 |
@el = '#' + @attributes['id'] |
| 10 | 10 |
@title = @attributes['title'] |
| 11 | 11 |
|
| 12 |
- @contacts = [] |
|
| 12 |
+ @contactViews = [] |
|
| 13 | 13 |
|
| 14 |
- @render() |
|
| 14 |
+ @createListContainer() |
|
| 15 | 15 |
|
| 16 |
- appendContact: (contact) -> |
|
| 17 |
- @contacts.push = new Xmpp.Views.Contacts.ContactView(model: contact, attributes: {listView: this})
|
|
| 18 |
- |
|
| 19 |
- render: (contacts) -> |
|
| 20 |
- contacts ||= [] |
|
| 21 |
- json_contacts = new Array(contacts.length) |
|
| 22 |
- _.each(contacts, (i, v) -> |
|
| 23 |
- json_contacts[i] = v.toJSON() |
|
| 24 |
- ) |
|
| 16 |
+ createListContainer: -> |
|
| 17 |
+ $(@el).html(@template(title: @title)) |
|
| 25 | 18 |
|
| 26 |
- $(@el).html(@template(title: @title, contacts: json_contacts)) |
|
| 27 | 19 |
\ No newline at end of file |
| 20 |
+ appendContact: (contact) -> |
|
| 21 |
+ view = new Xmpp.Views.Contacts.ContactView(model: contact, attributes: {listView: this})
|
|
| 22 |
+ @contactViews.push view |
|
| 23 |
+ @render(view.render().el) |
|
| 24 |
+ |
|
| 25 |
+ render: (contactHtml) -> |
|
| 26 |
+ if (contactHtml?) |
|
| 27 |
+ $(@el).find('ul').append(contactHtml)
|
|
| 28 |
+ else |
|
| 29 |
+ _.each(@contactViews, (i, contact) => |
|
| 30 |
+ @render(contact.render().el) |
|
| 31 |
+ ) |
|
| 32 |
+ |
|
| 33 |
+ return this |
|
| 28 | 34 |
\ No newline at end of file |
| ... | ... |
@@ -11,8 +11,12 @@ class WsRosterController < WebsocketRails::BaseController |
| 11 | 11 |
@storages.each do |storage| |
| 12 | 12 |
connection_store[storage] = [] |
| 13 | 13 |
end |
| 14 |
+ |
|
| 15 |
+ connection_store[:link_roster_client] = {}
|
|
| 14 | 16 |
end |
| 15 | 17 |
|
| 18 |
+ ## |
|
| 19 |
+ # Pripoj sa na jabber ucty. |
|
| 16 | 20 |
def connect |
| 17 | 21 |
initialize_storage() |
| 18 | 22 |
|
| ... | ... |
@@ -21,40 +25,83 @@ class WsRosterController < WebsocketRails::BaseController |
| 21 | 21 |
clients.each do |credentials| |
| 22 | 22 |
begin |
| 23 | 23 |
client = Signin.try_login(credentials["jid"], credentials["pass"]) |
| 24 |
- client.send(Jabber::Presence.new.set_type(:available)) |
|
| 25 |
- |
|
| 26 | 24 |
connection_store[:clients] << client |
| 27 |
- connection_store[:rosters] << Jabber::Roster::Helper.new(client) |
|
| 28 | 25 |
rescue Signin::LoginError |
| 29 |
- trigger_failure msg: credentials["jid"] |
|
| 26 |
+ send_message 'app.client.cannot_connect', true |
|
| 30 | 27 |
end |
| 31 | 28 |
end |
| 32 | 29 |
end |
| 33 | 30 |
|
| 34 | 31 |
## |
| 35 |
- # Vrat vsetkych priatelov v rosteri |
|
| 36 |
- def get_contacts |
|
| 37 |
- all_contacts = [] |
|
| 32 |
+ # Inicializuj roster so zoznamom ludi v nom. |
|
| 33 |
+ # Vrat zoznam ludi (ich JID). |
|
| 34 |
+ def init_roster |
|
| 35 |
+ all_jids = [] |
|
| 36 |
+ |
|
| 37 |
+ connection_store[:clients].each do |client| |
|
| 38 |
+ roster = Jabber::Roster::Helper.new(client) |
|
| 39 |
+ |
|
| 40 |
+ connection_store[:rosters] << roster |
|
| 41 |
+ connection_store[:link_roster_client][roster] = client |
|
| 38 | 42 |
|
| 39 |
- connection_store[:rosters].each do |roster| |
|
| 40 |
- roster.wait_for_roster |
|
| 41 | 43 |
roster.get_roster() |
| 44 |
+ roster.wait_for_roster() |
|
| 42 | 45 |
|
| 43 | 46 |
roster.items.each do |jid, contact| |
| 44 |
- all_contacts << {
|
|
| 45 |
- jid: jid.to_s |
|
| 46 |
- } |
|
| 47 |
+ all_jids << jid.to_s |
|
| 47 | 48 |
end |
| 48 | 49 |
end |
| 49 | 50 |
|
| 50 |
- trigger_success contacts: all_contacts |
|
| 51 |
+ trigger_success contacts: all_jids |
|
| 51 | 52 |
end |
| 52 | 53 |
|
| 53 |
- def disconnect |
|
| 54 |
- if connection_store[:clients] |
|
| 55 |
- connection_store[:clients].each do |client| |
|
| 56 |
- client.send(Jabber::Presence.new.set_type(:unavailable)) |
|
| 54 |
+ ## |
|
| 55 |
+ # Stiahni vcard ludi v rosteri |
|
| 56 |
+ def start_fetching_vcards |
|
| 57 |
+ connection_store[:rosters].each do |roster| |
|
| 58 |
+ client = connection_store[:link_roster_client][roster] |
|
| 59 |
+ |
|
| 60 |
+ roster.items.each do |jid, contact| |
|
| 61 |
+ Thread.new do |
|
| 62 |
+ vcard = get_vcard(client, jid.to_s) |
|
| 63 |
+ send_message 'app.roster.vcard', jid: jid.to_s, vcard: vcard |
|
| 64 |
+ end |
|
| 65 |
+ end |
|
| 66 |
+ end |
|
| 67 |
+ end |
|
| 68 |
+ |
|
| 69 |
+ ## |
|
| 70 |
+ # Zacni pocuvat zmeny stavov v rosteri |
|
| 71 |
+ def start_polling_contacts_state |
|
| 72 |
+ connection_store[:rosters].each do |roster| |
|
| 73 |
+ roster.add_presence_callback do |roster_item, old_presence, new_presence| |
|
| 74 |
+ if new_presence.type == :unavailable |
|
| 75 |
+ result = {status: :offline, message: ''}
|
|
| 76 |
+ else |
|
| 77 |
+ status = new_presence.show |
|
| 78 |
+ status = case status |
|
| 79 |
+ when :away, :xa then :away |
|
| 80 |
+ when :dnd then :dnd |
|
| 81 |
+ else :online |
|
| 82 |
+ end |
|
| 83 |
+ |
|
| 84 |
+ result = { status: status, message: new_presence.status.to_s }
|
|
| 85 |
+ end |
|
| 86 |
+ |
|
| 87 |
+ send_message 'app.roster.statusChanged', |
|
| 88 |
+ jid: roster_item.jid.strip.to_s, status: result |
|
| 57 | 89 |
end |
| 90 |
+ |
|
| 91 |
+ # ak by som poslal svoju Presence, tak add_presence_callback nezachyti |
|
| 92 |
+ # stav ludi, ktore sa odosielaju hned po zadani mojej Presence |
|
| 93 |
+ client = connection_store[:link_roster_client][roster] |
|
| 94 |
+ client.send(Jabber::Presence.new.set_type(:available)) |
|
| 95 |
+ end |
|
| 96 |
+ end |
|
| 97 |
+ |
|
| 98 |
+ def disconnect |
|
| 99 |
+ connection_store[:clients] && connection_store[:clients].each do |client| |
|
| 100 |
+ client.close() |
|
| 58 | 101 |
end |
| 59 | 102 |
|
| 60 | 103 |
@storages.each do |storage| |
| ... | ... |
@@ -67,4 +114,14 @@ class WsRosterController < WebsocketRails::BaseController |
| 67 | 67 |
def add_friend(data) |
| 68 | 68 |
|
| 69 | 69 |
end |
| 70 |
+ |
|
| 71 |
+ private |
|
| 72 |
+ |
|
| 73 |
+ def get_vcard(my_client, contacts_jid) |
|
| 74 |
+ vcard = Jabber::Vcard::Helper.get(my_client, contacts_jid) |
|
| 75 |
+ |
|
| 76 |
+ { name: vcard && (vcard["FN"] || vcard["NICKNAME"]) || contacts_jid,
|
|
| 77 |
+ avatar: '' #TODO avatar |
|
| 78 |
+ } |
|
| 79 |
+ end |
|
| 70 | 80 |
end |
| ... | ... |
@@ -42,14 +42,16 @@ WebsocketRails::EventMap.describe do |
| 42 | 42 |
# end |
| 43 | 43 |
# The above will handle an event triggered on the client like `product.new`. |
| 44 | 44 |
|
| 45 |
+ #toto asi poide do nadtriedy spajajucej roster a chat a ine veci |
|
| 45 | 46 |
subscribe :client_connected, to: WsRosterController, with_method: :connect |
| 46 | 47 |
subscribe :client_disconnected, to: WsRosterController, with_method: :disconnect |
| 47 | 48 |
|
| 48 | 49 |
namespace :app do |
| 49 | 50 |
|
| 50 | 51 |
namespace :roster do |
| 51 |
- subscribe :connect, to: WsRosterController, with_method: :connect |
|
| 52 |
- subscribe :contacts, to: WsRosterController, with_method: :get_contacts |
|
| 52 |
+ subscribe :initRoster, to: WsRosterController, with_method: :init_roster |
|
| 53 |
+ subscribe :startFetchingVcards, to: WsRosterController, with_method: :start_fetching_vcards |
|
| 54 |
+ subscribe :startPolling, to: WsRosterController, with_method: :start_polling_contacts_state |
|
| 53 | 55 |
end |
| 54 | 56 |
|
| 55 | 57 |
end |