... | ... |
@@ -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 |