vines 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. data/README +1 -1
  2. data/Rakefile +10 -10
  3. data/conf/certs/ca-bundle.crt +112 -378
  4. data/conf/config.rb +18 -9
  5. data/lib/vines.rb +8 -1
  6. data/lib/vines/command/cert.rb +2 -1
  7. data/lib/vines/command/init.rb +11 -0
  8. data/lib/vines/command/ldap.rb +6 -3
  9. data/lib/vines/command/schema.rb +1 -1
  10. data/lib/vines/config.rb +57 -146
  11. data/lib/vines/config/host.rb +85 -0
  12. data/lib/vines/config/port.rb +111 -0
  13. data/lib/vines/contact.rb +1 -1
  14. data/lib/vines/jid.rb +26 -4
  15. data/lib/vines/kit.rb +6 -0
  16. data/lib/vines/log.rb +24 -0
  17. data/lib/vines/router.rb +70 -38
  18. data/lib/vines/stanza.rb +45 -8
  19. data/lib/vines/stanza/iq.rb +3 -3
  20. data/lib/vines/stanza/iq/disco_info.rb +5 -1
  21. data/lib/vines/stanza/iq/disco_items.rb +3 -0
  22. data/lib/vines/stanza/iq/private_storage.rb +9 -5
  23. data/lib/vines/stanza/iq/roster.rb +11 -12
  24. data/lib/vines/stanza/iq/vcard.rb +4 -4
  25. data/lib/vines/stanza/iq/version.rb +25 -0
  26. data/lib/vines/stanza/message.rb +4 -5
  27. data/lib/vines/stanza/presence.rb +20 -18
  28. data/lib/vines/stanza/presence/probe.rb +3 -4
  29. data/lib/vines/stanza/presence/subscribe.rb +4 -3
  30. data/lib/vines/stanza/presence/subscribed.rb +6 -5
  31. data/lib/vines/stanza/presence/unsubscribe.rb +4 -4
  32. data/lib/vines/stanza/presence/unsubscribed.rb +4 -3
  33. data/lib/vines/storage/couchdb.rb +3 -3
  34. data/lib/vines/storage/ldap.rb +19 -8
  35. data/lib/vines/storage/local.rb +23 -12
  36. data/lib/vines/storage/redis.rb +3 -3
  37. data/lib/vines/storage/sql.rb +5 -5
  38. data/lib/vines/stream.rb +40 -6
  39. data/lib/vines/stream/client.rb +5 -6
  40. data/lib/vines/stream/client/auth.rb +3 -2
  41. data/lib/vines/stream/client/bind.rb +2 -2
  42. data/lib/vines/stream/client/bind_restart.rb +1 -2
  43. data/lib/vines/stream/client/ready.rb +2 -0
  44. data/lib/vines/stream/client/session.rb +13 -4
  45. data/lib/vines/stream/client/tls.rb +1 -0
  46. data/lib/vines/stream/component.rb +6 -5
  47. data/lib/vines/stream/component/ready.rb +5 -6
  48. data/lib/vines/stream/http.rb +10 -4
  49. data/lib/vines/stream/http/request.rb +23 -2
  50. data/lib/vines/stream/server.rb +13 -11
  51. data/lib/vines/stream/server/outbound/auth_result.rb +1 -0
  52. data/lib/vines/stream/server/outbound/tls_result.rb +1 -0
  53. data/lib/vines/stream/server/ready.rb +2 -2
  54. data/lib/vines/user.rb +2 -1
  55. data/lib/vines/version.rb +1 -1
  56. data/test/config/host_test.rb +292 -0
  57. data/test/config_test.rb +244 -103
  58. data/test/contact_test.rb +7 -1
  59. data/test/jid_test.rb +48 -0
  60. data/test/router_test.rb +16 -47
  61. data/test/stanza/iq/disco_info_test.rb +76 -0
  62. data/test/stanza/iq/disco_items_test.rb +47 -0
  63. data/test/stanza/iq/private_storage_test.rb +33 -10
  64. data/test/stanza/iq/roster_test.rb +15 -5
  65. data/test/stanza/iq/vcard_test.rb +8 -25
  66. data/test/stanza/iq/version_test.rb +62 -0
  67. data/test/stanza/iq_test.rb +13 -10
  68. data/test/stanza/message_test.rb +16 -24
  69. data/test/stanza/presence/probe_test.rb +52 -0
  70. data/test/stanza/presence/subscribe_test.rb +1 -5
  71. data/test/stanza_test.rb +77 -0
  72. data/test/stream/client/auth_test.rb +1 -0
  73. data/test/stream/client/ready_test.rb +2 -0
  74. data/test/stream/client/session_test.rb +7 -2
  75. data/test/stream/component/ready_test.rb +19 -36
  76. data/test/stream/http/request_test.rb +22 -2
  77. data/test/stream/server/ready_test.rb +14 -21
  78. data/web/404.html +9 -3
  79. data/web/chat/index.html +2 -2
  80. data/web/chat/javascripts/app.js +1 -1
  81. data/web/chat/stylesheets/chat.css +4 -9
  82. data/web/lib/coffeescripts/layout.coffee +2 -2
  83. data/web/{chat → lib}/coffeescripts/logout.coffee +0 -0
  84. data/web/lib/coffeescripts/notification.coffee +14 -0
  85. data/web/lib/coffeescripts/session.coffee +28 -24
  86. data/web/lib/coffeescripts/transfer.coffee +37 -34
  87. data/web/lib/javascripts/base.js +8 -8
  88. data/web/lib/javascripts/icons.js +3 -0
  89. data/web/lib/javascripts/jquery.js +4 -18
  90. data/web/lib/javascripts/layout.js +2 -2
  91. data/web/{chat → lib}/javascripts/logout.js +0 -0
  92. data/web/lib/javascripts/notification.js +26 -0
  93. data/web/lib/javascripts/session.js +20 -16
  94. data/web/lib/javascripts/transfer.js +45 -55
  95. data/web/lib/stylesheets/base.css +45 -9
  96. metadata +31 -15
@@ -28,14 +28,11 @@ class SubscribeTest < MiniTest::Unit::TestCase
28
28
  @nodes << node
29
29
  end
30
30
 
31
- router = MiniTest::Mock.new
32
- router.expect(:interested_resources, [recipient], [alice])
33
-
34
31
  stream = MiniTest::Mock.new
35
32
  stream.expect(:domain, 'wonderland.lit')
36
33
  stream.expect(:storage, storage, ['wonderland.lit'])
37
34
  stream.expect(:user, user)
38
- stream.expect(:router, router)
35
+ stream.expect(:interested_resources, [recipient], [alice])
39
36
  stream.expect(:update_user_streams, nil, [user])
40
37
  def stream.nodes; @nodes; end
41
38
  def stream.write(node)
@@ -53,7 +50,6 @@ class SubscribeTest < MiniTest::Unit::TestCase
53
50
  assert stream.verify
54
51
  assert user.verify
55
52
  assert storage.verify
56
- assert router.verify
57
53
  assert_equal 1, stream.nodes.size
58
54
  assert_equal 1, recipient.nodes.size
59
55
 
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'vines'
4
+ require 'ext/nokogiri'
5
+ require 'minitest/autorun'
6
+
7
+ class StanzaTest < MiniTest::Unit::TestCase
8
+ def setup
9
+ @alice = Vines::JID.new('alice@wonderland.lit/tea')
10
+ @romeo = Vines::JID.new('romeo@verona.lit/balcony')
11
+ @stream = MiniTest::Mock.new
12
+ @config = Vines::Config.new do
13
+ host 'wonderland.lit' do
14
+ storage(:fs) { dir '.' }
15
+ end
16
+ end
17
+ end
18
+
19
+ def test_validate_missing_addresses
20
+ node = node(%Q{<message>hello!</message>})
21
+ stanza = Vines::Stanza::Message.new(node, @stream)
22
+ assert_nil stanza.validate_to
23
+ assert_nil stanza.validate_from
24
+ assert @stream.verify
25
+ end
26
+
27
+ def test_validate_valid_addresses
28
+ node = node(%Q{<message from="#{@alice}" to="#{@romeo}">hello!</message>})
29
+ stanza = Vines::Stanza::Message.new(node, @stream)
30
+ assert_equal @romeo, stanza.validate_to
31
+ assert_equal @alice, stanza.validate_from
32
+ assert @stream.verify
33
+ end
34
+
35
+ def test_validate_invalid_addresses
36
+ node = node(%Q{<message from="a lice@wonderland.lit" to="romeo@v erona.lit">hello!</message>})
37
+ stanza = Vines::Stanza::Message.new(node, @stream)
38
+ assert_raises(Vines::StanzaErrors::JidMalformed) { stanza.validate_to }
39
+ assert_raises(Vines::StanzaErrors::JidMalformed) { stanza.validate_from }
40
+ assert @stream.verify
41
+ end
42
+
43
+ def test_non_routable_stanza_is_local
44
+ stanza = Vines::Stanza.new(node('<auth/>'), @stream)
45
+ assert stanza.local?
46
+ assert @stream.verify
47
+ end
48
+
49
+ def test_stanza_missing_to_is_local
50
+ node = node(%Q{<message>hello!</message>})
51
+ stanza = Vines::Stanza::Message.new(node, @stream)
52
+ assert stanza.local?
53
+ assert @stream.verify
54
+ end
55
+
56
+ def test_stanza_with_local_jid_is_local
57
+ node = node(%Q{<message to="#{@alice}">hello!</message>})
58
+ @stream.expect(:config, @config)
59
+ stanza = Vines::Stanza::Message.new(node, @stream)
60
+ assert stanza.local?
61
+ assert @stream.verify
62
+ end
63
+
64
+ def test_stanza_with_remote_jid_is_not_local
65
+ node = node(%Q{<message to="#{@romeo}">hello!</message>})
66
+ @stream.expect(:config, @config)
67
+ stanza = Vines::Stanza::Message.new(node, @stream)
68
+ refute stanza.local?
69
+ assert @stream.verify
70
+ end
71
+
72
+ private
73
+
74
+ def node(xml)
75
+ Nokogiri::XML(xml).root
76
+ end
77
+ end
@@ -90,6 +90,7 @@ class ClientAuthTest < MiniTest::Unit::TestCase
90
90
 
91
91
  def test_plain_auth_valid_password
92
92
  user = Vines::User.new(:jid => 'alice@wonderland.lit')
93
+ @stream.expect(:reset, nil)
93
94
  @stream.expect(:storage, MockStorage.new)
94
95
  @stream.expect(:user, user)
95
96
  @stream.expect(:user=, nil, [user])
@@ -15,6 +15,8 @@ class ClientReadyTest < MiniTest::Unit::TestCase
15
15
  else
16
16
  MiniTest::Mock.new.tap do |stanza|
17
17
  stanza.expect(:process, nil)
18
+ stanza.expect(:validate_to, nil)
19
+ stanza.expect(:validate_from, nil)
18
20
  ClientReadyTest::STANZAS << stanza
19
21
  end
20
22
  end
@@ -4,9 +4,14 @@ require 'vines'
4
4
  require 'minitest/autorun'
5
5
 
6
6
  class ClientSessionTest < MiniTest::Unit::TestCase
7
+ def setup
8
+ @stream = MiniTest::Mock.new
9
+ @stream.expect(:config, nil)
10
+ end
11
+
7
12
  def test_equality
8
- one = Vines::Stream::Client::Session.new(nil)
9
- two = Vines::Stream::Client::Session.new(nil)
13
+ one = Vines::Stream::Client::Session.new(@stream)
14
+ two = Vines::Stream::Client::Session.new(@stream)
10
15
 
11
16
  assert_nil one <=> 42
12
17
 
@@ -5,94 +5,77 @@ require 'ext/nokogiri'
5
5
  require 'minitest/autorun'
6
6
 
7
7
  class ComponentReadyTest < MiniTest::Unit::TestCase
8
- STANZAS = []
9
-
10
8
  def setup
11
9
  @stream = MiniTest::Mock.new
12
- @state = Vines::Stream::Component::Ready.new(@stream, nil)
13
- def @state.to_stanza(node)
14
- if node.name == 'bogus'
15
- nil
16
- else
17
- MiniTest::Mock.new.tap do |stanza|
18
- if node['to'] == 'hatter@wonderland.lit'
19
- stanza.expect(:local?, true)
20
- else
21
- stanza.expect(:local?, false)
22
- stanza.expect(:route, nil)
23
- end
24
- ComponentReadyTest::STANZAS << stanza
25
- end
10
+ @state = Vines::Stream::Component::Ready.new(@stream, nil)
11
+ @config = Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ storage(:fs) { dir '.' }
26
14
  end
27
15
  end
28
16
  end
29
17
 
30
- def teardown
31
- STANZAS.clear
32
- end
33
-
34
18
  def test_missing_to_and_from_addresses
35
19
  node = node('<message/>')
36
20
  assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
37
- assert_equal 1, STANZAS.size
38
21
  assert @stream.verify
39
22
  end
40
23
 
41
24
  def test_missing_from_address
42
- @stream.expect(:remote_domain, 'tea.wonderland.lit')
43
25
  node = node(%q{<message to="hatter@wonderland.lit"/>})
44
26
  assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
45
- assert_equal 1, STANZAS.size
46
27
  assert @stream.verify
47
28
  end
48
29
 
49
30
  def test_missing_to_address
50
31
  node = node(%q{<message from="alice@tea.wonderland.lit"/>})
51
32
  assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
52
- assert_equal 1, STANZAS.size
53
33
  assert @stream.verify
54
34
  end
55
35
 
56
36
  def test_invalid_from_address
57
37
  @stream.expect(:remote_domain, 'tea.wonderland.lit')
58
38
  node = node(%q{<message from="alice@bogus.wonderland.lit" to="hatter@wonderland.lit"/>})
59
- assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
60
- assert_equal 1, STANZAS.size
39
+ assert_raises(Vines::StreamErrors::InvalidFrom) { @state.node(node) }
61
40
  assert @stream.verify
62
41
  end
63
42
 
64
43
  def test_unsupported_stanza_type
65
44
  node = node('<bogus/>')
66
45
  assert_raises(Vines::StreamErrors::UnsupportedStanzaType) { @state.node(node) }
67
- assert STANZAS.empty?
68
46
  assert @stream.verify
69
47
  end
70
48
 
71
49
  def test_remote_message_routes
72
- @stream.expect(:remote_domain, 'tea.wonderland.lit')
73
50
  node = node(%q{<message from="alice@tea.wonderland.lit" to="romeo@verona.lit"/>})
51
+ @stream.expect(:remote_domain, 'tea.wonderland.lit')
52
+ @stream.expect(:config, @config)
53
+ @stream.expect(:user=, nil, [Vines::User.new(:jid => 'alice@tea.wonderland.lit')])
54
+
55
+ @router = MiniTest::Mock.new
56
+ @router.expect(:route, nil, [node])
57
+ @stream.expect(:router, @router)
58
+
74
59
  @state.node(node)
75
- assert_equal 1, STANZAS.size
76
- assert STANZAS.map {|s| s.verify }.all?
77
60
  assert @stream.verify
61
+ assert @router.verify
78
62
  end
79
63
 
80
64
  def test_local_message_processes
81
65
  node = node(%q{<message from="alice@tea.wonderland.lit" to="hatter@wonderland.lit"/>})
82
66
  @stream.expect(:remote_domain, 'tea.wonderland.lit')
67
+ @stream.expect(:config, @config)
68
+ @stream.expect(:user=, nil, [Vines::User.new(:jid => 'alice@tea.wonderland.lit')])
69
+ @stream.expect(:user, Vines::User.new(:jid => 'alice@tea.wonderland.lit'))
83
70
 
84
71
  @recipient = MiniTest::Mock.new
72
+ @recipient.expect(:user, Vines::User.new(:jid => 'hatter@wonderland.lit'))
85
73
  @recipient.expect(:write, nil, [node])
86
74
 
87
- @router = MiniTest::Mock.new
88
- @router.expect(:connected_resources, [@recipient], ['hatter@wonderland.lit'])
89
- @stream.expect(:router, @router)
75
+ @stream.expect(:connected_resources, [@recipient], ['hatter@wonderland.lit'])
90
76
 
91
77
  @state.node(node)
92
- assert_equal 1, STANZAS.size
93
- assert STANZAS.map {|s| s.verify }.all?
94
78
  assert @stream.verify
95
- assert @router.verify
96
79
  assert @recipient.verify
97
80
  end
98
81
 
@@ -13,7 +13,7 @@ class RequestTest < MiniTest::Unit::TestCase
13
13
 
14
14
  @stream = MiniTest::Mock.new
15
15
  @parser = MiniTest::Mock.new
16
- @parser.expect(:headers, {'Content-Type' => 'text/html'})
16
+ @parser.expect(:headers, {'Content-Type' => 'text/html', 'Host' => 'wonderland.lit'})
17
17
  @parser.expect(:http_method, 'GET')
18
18
  @parser.expect(:request_path, '/blogs/12')
19
19
  @parser.expect(:request_url, '/blogs/12?ok=true')
@@ -27,7 +27,7 @@ class RequestTest < MiniTest::Unit::TestCase
27
27
 
28
28
  def test_copies_request_info_from_parser
29
29
  request = Vines::Stream::Http::Request.new(@stream, @parser, '<html></html>')
30
- assert_equal request.headers, {'Content-Type' => 'text/html'}
30
+ assert_equal request.headers, {'Content-Type' => 'text/html', 'Host' => 'wonderland.lit'}
31
31
  assert_equal request.method, 'GET'
32
32
  assert_equal request.path, '/blogs/12'
33
33
  assert_equal request.url, '/blogs/12?ok=true'
@@ -64,6 +64,7 @@ class RequestTest < MiniTest::Unit::TestCase
64
64
 
65
65
  def test_reply_with_file_for_directory_serves_index_html
66
66
  @parser.expect(:request_path, '/')
67
+ @parser.expect(:request_url, '/?ok=true')
67
68
  request = Vines::Stream::Http::Request.new(@stream, @parser, '<html></html>')
68
69
 
69
70
  mtime = File.mtime(INDEX).utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
@@ -83,4 +84,23 @@ class RequestTest < MiniTest::Unit::TestCase
83
84
  assert @stream.verify
84
85
  assert @parser.verify
85
86
  end
87
+
88
+ def test_reply_with_file_redirects_for_missing_slash
89
+ @parser.expect(:request_path, '/http')
90
+ @parser.expect(:request_url, '/http?ok=true')
91
+ request = Vines::Stream::Http::Request.new(@stream, @parser, '<html></html>')
92
+
93
+ headers = [
94
+ "HTTP/1.1 301 Moved Permanently",
95
+ "Connection: close",
96
+ "Location: http://wonderland.lit/http/?ok=true"
97
+ ].join("\r\n")
98
+
99
+ @stream.expect(:stream_write, nil, ["#{headers}\r\n\r\n"])
100
+ @stream.expect(:close_connection_after_writing, nil)
101
+ # so the /http url above will work
102
+ request.reply_with_file(File.expand_path('../../', __FILE__))
103
+ assert @stream.verify
104
+ assert @parser.verify
105
+ end
86
106
  end
@@ -10,16 +10,10 @@ class ServerReadyTest < MiniTest::Unit::TestCase
10
10
  @stream = MiniTest::Mock.new
11
11
  @state = Vines::Stream::Server::Ready.new(@stream, nil)
12
12
  def @state.to_stanza(node)
13
- if node.name == 'bogus'
14
- nil
15
- else
16
- MiniTest::Mock.new.tap do |stanza|
17
- stanza.expect(:process, nil)
18
- stanza.class.send(:define_method, :[]) do |a|
19
- node[a]
20
- end
21
- ServerReadyTest::STANZAS << stanza
22
- end
13
+ Vines::Stanza.from_node(node, @stream).tap do |stanza|
14
+ def stanza.process
15
+ ServerReadyTest::STANZAS << self
16
+ end if stanza
23
17
  end
24
18
  end
25
19
  end
@@ -35,7 +29,6 @@ class ServerReadyTest < MiniTest::Unit::TestCase
35
29
  node = node(%Q{<message from="alice@wonderland.lit" to="romeo@verona.lit"/>})
36
30
  @state.node(node)
37
31
  assert_equal 1, STANZAS.size
38
- assert STANZAS.map {|s| s.verify }.all?
39
32
  assert @stream.verify
40
33
  end
41
34
 
@@ -49,28 +42,28 @@ class ServerReadyTest < MiniTest::Unit::TestCase
49
42
  def test_improper_addressing_missing_to
50
43
  node = node(%Q{<message from="alice@wonderland.lit"/>})
51
44
  assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
52
- assert_equal 1, STANZAS.size
45
+ assert STANZAS.empty?
53
46
  assert @stream.verify
54
47
  end
55
48
 
56
- def test_improper_addressing_empty_to
49
+ def test_improper_addressing_invalid_to
57
50
  node = node(%Q{<message from="alice@wonderland.lit" to=" "/>})
58
- assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
59
- assert_equal 1, STANZAS.size
51
+ assert_raises(Vines::StanzaErrors::JidMalformed) { @state.node(node) }
52
+ assert STANZAS.empty?
60
53
  assert @stream.verify
61
54
  end
62
55
 
63
56
  def test_improper_addressing_missing_from
64
57
  node = node(%Q{<message to="romeo@verona.lit"/>})
65
58
  assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
66
- assert_equal 1, STANZAS.size
59
+ assert STANZAS.empty?
67
60
  assert @stream.verify
68
61
  end
69
62
 
70
- def test_improper_addressing_empty_from
63
+ def test_improper_addressing_invalid_from
71
64
  node = node(%Q{<message from=" " to="romeo@verona.lit"/>})
72
- assert_raises(Vines::StreamErrors::ImproperAddressing) { @state.node(node) }
73
- assert_equal 1, STANZAS.size
65
+ assert_raises(Vines::StanzaErrors::JidMalformed) { @state.node(node) }
66
+ assert STANZAS.empty?
74
67
  assert @stream.verify
75
68
  end
76
69
 
@@ -78,7 +71,7 @@ class ServerReadyTest < MiniTest::Unit::TestCase
78
71
  @stream.expect(:remote_domain, 'wonderland.lit')
79
72
  node = node(%Q{<message from="alice@bogus.lit" to="romeo@verona.lit"/>})
80
73
  assert_raises(Vines::StreamErrors::InvalidFrom) { @state.node(node) }
81
- assert_equal 1, STANZAS.size
74
+ assert STANZAS.empty?
82
75
  assert @stream.verify
83
76
  end
84
77
 
@@ -87,7 +80,7 @@ class ServerReadyTest < MiniTest::Unit::TestCase
87
80
  @stream.expect(:domain, 'verona.lit')
88
81
  node = node(%Q{<message from="alice@wonderland.lit" to="romeo@bogus.lit"/>})
89
82
  assert_raises(Vines::StreamErrors::HostUnknown) { @state.node(node) }
90
- assert_equal 1, STANZAS.size
83
+ assert STANZAS.empty?
91
84
  assert @stream.verify
92
85
  end
93
86
 
data/web/404.html CHANGED
@@ -27,17 +27,23 @@
27
27
  width: 100%;
28
28
  }
29
29
  p {
30
- color: #fff;
30
+ color: rgba(255, 255, 255, 0.8);
31
31
  font-size: 11pt;
32
32
  margin: 20px auto;
33
- text-shadow: 0 1px 1px #000;
33
+ width: 400px;
34
+ }
35
+ a {
36
+ color: inherit;
34
37
  }
35
38
  </style>
36
39
  </head>
37
40
  <body>
38
41
  <header>
39
42
  <h1>Page not found</h1>
40
- <p>This is not the page you're looking for.</p>
43
+ <p>
44
+ This is not the page you're looking for. You probably wanted the
45
+ <a href="/chat/">chat</a> application.
46
+ </p>
41
47
  </header>
42
48
  </body>
43
49
  </html>
data/web/chat/index.html CHANGED
@@ -8,9 +8,9 @@
8
8
  <link rel="shortcut icon" type="image/png" href="/favicon.png">
9
9
  <link rel="stylesheet" href="/lib/stylesheets/base.css">
10
10
  <link rel="stylesheet" href="/lib/stylesheets/login.css">
11
- <link rel="stylesheet" href="/chat/stylesheets/chat.css">
11
+ <link rel="stylesheet" href="stylesheets/chat.css">
12
12
  <script type="text/javascript" src="/lib/javascripts/base.js"></script>
13
- <script type="text/javascript" src="/chat/javascripts/app.js"></script>
13
+ <script type="text/javascript" src="javascripts/app.js"></script>
14
14
  </head>
15
15
  <body>
16
16
  </body>
@@ -1 +1 @@
1
- var ChatPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ChatPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onCard(__bind(function(a){return this.card(a)},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.chats={},this.currentContact=null}a.prototype.datef=function(a){var b,c,d,e;b=new Date(a),d=b.getHours()>=12?" pm":" am",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e);return c+":"+e+d},a.prototype.card=function(a){return this.eachContact(a.jid,__bind(function(b){return $(".vcard-img",b).attr("src",this.session.avatar(a.jid))},this))},a.prototype.roster=function(){var a,b,c,d,e,f,g,h;e=$("#roster"),$("li",e).each(__bind(function(a,b){var c;c=$(b).attr("data-jid");if(!this.session.roster[c])return $(b).remove()},this)),f=function(a,b){$(".text",a).text(b.name||b.jid);return a.attr("data-name",b.name||"")},g=this.session.roster,h=[];for(c in g)a=g[c],b=$("#roster li[data-jid='"+c+"']"),f(b,a),h.push(b.length===0?(d=$('<li data-jid="'+c+'" data-name="" class="offline">\n <span class="text"></span>\n <span class="status-msg">Offline</span>\n <span class="unread" style="display:none;"></span>\n <img class="vcard-img" alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n</li>').appendTo(e),f(d,a),d.click(__bind(function(a){return this.selectContact(a)},this))):void 0);return h},a.prototype.message=function(a){var b,c,d,e;this.queueMessage(a),e=a.from===this.session.jid(),d=a.from.split("/")[0];if(!e&&d!==this.currentContact){c=this.chat(a.from),c.unread++;return this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()})}b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll()},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster li[data-jid='"+a+"']").get(),g=[];for(d=0,e=f.length;d<e;d++)c=f[d],g.push(b($(c)));return g},a.prototype.appendMessage=function(a){var b,c,d,e;c=a.from.split("/")[0],b=this.session.roster[c],d=b?b.name||c:c,a.from===this.session.jid()&&(d="Me"),e=$('<li data-jid="'+c+'" style="display:none;">\n <p></p>\n <img alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n <footer>\n <span class="author"></span>\n <span class="time">'+this.datef(a.received)+"</span>\n </footer>\n</li>").appendTo("#messages"),$("p",e).text(a.text),$(".author",e).text(d);return e.fadeIn(200)},a.prototype.queueMessage=function(a){var b,c,d;d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c;return b.messages.push(a)},a.prototype.chat=function(a){var b,c;b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c);return c},a.prototype.presence=function(a){var b,c,d;c=a.from.split("/")[0];if(c!==this.session.bareJid()){if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){$(".status-msg",a).text(b.status());return b.offline()?a.addClass("offline"):a.removeClass("offline")});a.offline&&(this.chat(c).jid=c);if(a.type==="subscribe"){d=$('<li data-jid="'+a.from+'" style="display:none;">\n <form class="inset">\n <h2>Buddy Approval</h2>\n <p>'+a.from+' wants to add you as a buddy.</p>\n <fieldset class="buttons">\n <input type="button" value="Decline"/>\n <input type="submit" value="Accept"/>\n </fieldset>\n </form>\n</li>').appendTo("#notifications"),d.fadeIn(200),$("form",d).submit(__bind(function(){return this.acceptContact(d,a.from)},this));return $('input[type="button"]',d).click(__bind(function(){return this.rejectContact(d,a.from)},this))}}},a.prototype.acceptContact=function(a,b){a.fadeOut(200,function(){return a.remove()}),this.session.sendSubscribed(b),this.session.sendSubscribe(b);return!1},a.prototype.rejectContact=function(a,b){a.fadeOut(200,function(){return a.remove()});return this.session.sendUnsubscribed(b)},a.prototype.selectContact=function(a){var b,c,d,e,f,g,h;d=$(a.currentTarget).attr("data-jid"),c=this.session.roster[d];if(this.currentContact!==d){this.currentContact=d,$("#roster li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#chat-title").text("Chat with "+(c.name||c.jid)),$("#messages").empty(),b=this.chats[d],e=[],b&&(e=b.messages,b.unread=0,this.eachContact(d,function(a){return $(".unread",a).text("").hide()}));for(g=0,h=e.length;g<h;g++)f=e[g],this.appendMessage(f);this.scroll(),$("#remove-contact-msg").html("Are you sure you want to remove "+("<strong>"+this.currentContact+"</strong> from your buddy list?")),$("#remove-contact-form .buttons").fadeIn(200),$("#edit-contact-jid").text(this.currentContact),$("#edit-contact-name").val(this.session.roster[this.currentContact].name),$("#edit-contact-form input").fadeIn(200);return $("#edit-contact-form .buttons").fadeIn(200)}},a.prototype.scroll=function(){var a;a=$("#messages");return a.animate({scrollTop:a.prop("scrollHeight")},400)},a.prototype.atBottom=function(){var a,b;b=$("#messages"),a=b.prop("scrollHeight")-b.height();return b.scrollTop()===a},a.prototype.send=function(){var a,b,c,d;if(!this.currentContact)return!1;b=$("#message"),d=b.val().trim(),d&&(a=this.chats[this.currentContact],c=a?a.jid:this.currentContact,this.message({from:this.session.jid(),text:d,to:c,received:new Date}),this.session.sendMessage(c,d)),b.val("");return!1},a.prototype.addContact=function(){var a;this.toggleForm("#add-contact-form"),a={jid:$("#add-contact-jid").val(),name:$("#add-contact-name").val(),groups:["Buddies"]},a.jid&&this.session.updateContact(a,!0);return!1},a.prototype.removeContact=function(){this.toggleForm("#remove-contact-form"),this.session.removeContact(this.currentContact),this.currentContact=null,$("#chat-title").text("Select a buddy to chat"),$("#messages").empty(),$("#remove-contact-msg").html("Select a buddy in the list above to remove."),$("#remove-contact-form .buttons").hide(),$("#edit-contact-jid").text("Select a buddy in the list above to update."),$("#edit-contact-name").val(""),$("#edit-contact-form input").hide(),$("#edit-contact-form .buttons").hide();return!1},a.prototype.updateContact=function(){var a;this.toggleForm("#edit-contact-form"),a={jid:this.currentContact,name:$("#edit-contact-name").val(),groups:this.session.roster[this.currentContact].groups},this.session.updateContact(a);return!1},a.prototype.toggleForm=function(a,b){a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()});if(a.is(":hidden")){b&&b();return a.fadeIn(100)}return a.fadeOut(100,function(){a[0].reset();if(b)return b()})},a.prototype.draw=function(){var a,b;if(!this.session.connected())window.location.hash="";else{$("body").attr("id","chat-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Buddies <div id="search-roster-icon"></div></h2>\n <div id="search-roster-form"></div>\n <ul id="roster" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-contact"></div>\n <div id="remove-contact"></div>\n <div id="edit-contact"></div>\n </div>\n <form id="add-contact-form" class="overlay" style="display:none;">\n <h2>Add Buddy</h2>\n <input id="add-contact-jid" type="email" maxlength="1024" placeholder="Account name"/>\n <input id="add-contact-name" type="text" maxlength="1024" placeholder="Real name"/>\n <fieldset class="buttons">\n <input id="add-contact-cancel" type="button" value="Cancel"/>\n <input id="add-contact-ok" type="submit" value="Add"/>\n </fieldset>\n </form>\n <form id="remove-contact-form" class="overlay" style="display:none;">\n <h2>Remove Buddy</h2>\n <p id="remove-contact-msg">Select a buddy in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-contact-cancel" type="button" value="Cancel"/>\n <input id="remove-contact-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <form id="edit-contact-form" class="overlay" style="display:none;">\n <h2>Update Profile</h2>\n <p id="edit-contact-jid">Select a buddy in the list above to update.</p>\n <input id="edit-contact-name" type="text" maxlength="1024" placeholder="Real name" style="display:none;"/>\n <fieldset class="buttons" style="display:none;">\n <input id="edit-contact-cancel" type="button" value="Cancel"/>\n <input id="edit-contact-ok" type="submit" value="Save"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="chat-title">Select a buddy to chat</h2>\n <ul id="messages" class="scroll y-fill"></ul>\n <form id="message-form">\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a message and press enter to send"/>\n </form>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Notifications</h2>\n <ul id="notifications" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <div id="clear-notices"></div>\n </div>\n</div>').appendTo("#container"),this.roster(),new Button("#clear-notices",ICONS.no),new Button("#add-contact",ICONS.plus),new Button("#remove-contact",ICONS.minus),new Button("#edit-contact",ICONS.user),$("#message").focus(function(){return $("form.overlay").fadeOut()}),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#clear-notices").click(function(){return $("#notifications li").fadeOut(200)}),$("#add-contact").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact").click(__bind(function(){return this.toggleForm("#edit-contact-form",__bind(function(){if(this.currentContact){$("#edit-contact-jid").text(this.currentContact);return $("#edit-contact-name").val(this.session.roster[this.currentContact].name)}},this))},this)),$("#add-contact-cancel").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact-cancel").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact-cancel").click(__bind(function(){return this.toggleForm("#edit-contact-form")},this)),$("#add-contact-form").submit(__bind(function(){return this.addContact()},this)),$("#remove-contact-form").submit(__bind(function(){return this.removeContact()},this)),$("#edit-contact-form").submit(__bind(function(){return this.updateContact()},this)),$("#container").fadeIn(200),b=this.resize(),a=function(){b.resize();return b.resize()};return new Filter({list:"#roster",icon:"#search-roster-icon",form:"#search-roster-form",attrs:["data-jid","data-name"],open:a,close:a})}},a.prototype.resize=function(){var a,b,c,d,e;a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#message"),d=$("#message-form");return new Layout(function(){c.css("left",a.width()+b.width());return e.width(d.width()-32)})};return a}();var LogoutPage;LogoutPage=function(){function a(a){this.session=a}a.prototype.draw=function(){window.location.hash="";return window.location.reload()};return a}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Messages:ICONS.chat,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);e={"/messages":new ChatPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/messages/")},(new Router(e)).draw();return d.select($("#nav-link-messages").parent())})
1
+ var ChatPage,__bind=function(a,b){return function(){return a.apply(b,arguments)}};ChatPage=function(){function a(a){this.session=a,this.session.onRoster(__bind(function(){return this.roster()},this)),this.session.onCard(__bind(function(a){return this.card(a)},this)),this.session.onMessage(__bind(function(a){return this.message(a)},this)),this.session.onPresence(__bind(function(a){return this.presence(a)},this)),this.chats={},this.currentContact=null}return a.prototype.datef=function(a){var b,c,d,e;return b=new Date(a),d=b.getHours()<12?" am":" pm",c=b.getHours()>12?b.getHours()-12:b.getHours(),c===0&&(c=12),e=b.getMinutes()+"",e.length===1&&(e="0"+e),c+":"+e+d},a.prototype.card=function(a){return this.eachContact(a.jid,__bind(function(b){return $(".vcard-img",b).attr("src",this.session.avatar(a.jid))},this))},a.prototype.roster=function(){var a,b,c,d,e,f,g,h;e=$("#roster"),$("li",e).each(__bind(function(a,b){var c;c=$(b).attr("data-jid");if(!this.session.roster[c])return $(b).remove()},this)),f=function(a,b){return $(".text",a).text(b.name||b.jid),a.attr("data-name",b.name||"")},g=this.session.roster,h=[];for(c in g)a=g[c],b=$("#roster li[data-jid='"+c+"']"),f(b,a),h.push(b.length===0?(d=$('<li data-jid="'+c+'" data-name="" class="offline">\n <span class="text"></span>\n <span class="status-msg">Offline</span>\n <span class="unread" style="display:none;"></span>\n <img class="vcard-img" alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n</li>').appendTo(e),f(d,a),d.click(__bind(function(a){return this.selectContact(a)},this))):void 0);return h},a.prototype.message=function(a){var b,c,d,e;this.queueMessage(a),e=a.from===this.session.jid(),d=a.from.split("/")[0];if(!e&&d!==this.currentContact)return c=this.chat(a.from),c.unread++,this.eachContact(d,function(a){return $(".unread",a).text(c.unread).show()});b=this.atBottom(),this.appendMessage(a);if(b)return this.scroll()},a.prototype.eachContact=function(a,b){var c,d,e,f,g;f=$("#roster li[data-jid='"+a+"']").get(),g=[];for(d=0,e=f.length;d<e;d++)c=f[d],g.push(b($(c)));return g},a.prototype.appendMessage=function(a){var b,c,d,e;return c=a.from.split("/")[0],b=this.session.roster[c],d=b?b.name||c:c,a.from===this.session.jid()&&(d="Me"),e=$('<li data-jid="'+c+'" style="display:none;">\n <p></p>\n <img alt="'+c+'" src="'+this.session.avatar(c)+'"/>\n <footer>\n <span class="author"></span>\n <span class="time">'+this.datef(a.received)+"</span>\n </footer>\n</li>").appendTo("#messages"),$("p",e).text(a.text),$(".author",e).text(d),e.fadeIn(200)},a.prototype.queueMessage=function(a){var b,c,d;return d=a.from===this.session.jid(),c=a[d?"to":"from"],b=this.chat(c),b.jid=c,b.messages.push(a)},a.prototype.chat=function(a){var b,c;return b=a.split("/")[0],c=this.chats[b],c||(c={jid:a,messages:[],unread:0},this.chats[b]=c),c},a.prototype.presence=function(a){var b,c,d;c=a.from.split("/")[0];if(c===this.session.bareJid())return;if(!a.type||a.offline)b=this.session.roster[c],this.eachContact(c,function(a){return $(".status-msg",a).text(b.status()),b.offline()?a.addClass("offline"):a.removeClass("offline")});a.offline&&(this.chat(c).jid=c);if(a.type==="subscribe")return d=$('<li data-jid="'+a.from+'" style="display:none;">\n <form class="inset">\n <h2>Buddy Approval</h2>\n <p>'+a.from+' wants to add you as a buddy.</p>\n <fieldset class="buttons">\n <input type="button" value="Decline"/>\n <input type="submit" value="Accept"/>\n </fieldset>\n </form>\n</li>').appendTo("#notifications"),d.fadeIn(200),$("form",d).submit(__bind(function(){return this.acceptContact(d,a.from)},this)),$('input[type="button"]',d).click(__bind(function(){return this.rejectContact(d,a.from)},this))},a.prototype.acceptContact=function(a,b){return a.fadeOut(200,function(){return a.remove()}),this.session.sendSubscribed(b),this.session.sendSubscribe(b),!1},a.prototype.rejectContact=function(a,b){return a.fadeOut(200,function(){return a.remove()}),this.session.sendUnsubscribed(b)},a.prototype.selectContact=function(a){var b,c,d,e,f,g,h;d=$(a.currentTarget).attr("data-jid"),c=this.session.roster[d];if(this.currentContact===d)return;this.currentContact=d,$("#roster li").removeClass("selected"),$(a.currentTarget).addClass("selected"),$("#chat-title").text("Chat with "+(c.name||c.jid)),$("#messages").empty(),b=this.chats[d],e=[],b&&(e=b.messages,b.unread=0,this.eachContact(d,function(a){return $(".unread",a).text("").hide()}));for(g=0,h=e.length;g<h;g++)f=e[g],this.appendMessage(f);return this.scroll(),$("#remove-contact-msg").html("Are you sure you want to remove "+("<strong>"+this.currentContact+"</strong> from your buddy list?")),$("#remove-contact-form .buttons").fadeIn(200),$("#edit-contact-jid").text(this.currentContact),$("#edit-contact-name").val(this.session.roster[this.currentContact].name),$("#edit-contact-form input").fadeIn(200),$("#edit-contact-form .buttons").fadeIn(200)},a.prototype.scroll=function(){var a;return a=$("#messages"),a.animate({scrollTop:a.prop("scrollHeight")},400)},a.prototype.atBottom=function(){var a,b;return b=$("#messages"),a=b.prop("scrollHeight")-b.height(),b.scrollTop()===a},a.prototype.send=function(){var a,b,c,d;return this.currentContact?(b=$("#message"),d=b.val().trim(),d&&(a=this.chats[this.currentContact],c=a?a.jid:this.currentContact,this.message({from:this.session.jid(),text:d,to:c,received:new Date}),this.session.sendMessage(c,d)),b.val(""),!1):!1},a.prototype.addContact=function(){var a;return this.toggleForm("#add-contact-form"),a={jid:$("#add-contact-jid").val(),name:$("#add-contact-name").val(),groups:["Buddies"]},a.jid&&this.session.updateContact(a,!0),!1},a.prototype.removeContact=function(){return this.toggleForm("#remove-contact-form"),this.session.removeContact(this.currentContact),this.currentContact=null,$("#chat-title").text("Select a buddy to chat"),$("#messages").empty(),$("#remove-contact-msg").html("Select a buddy in the list above to remove."),$("#remove-contact-form .buttons").hide(),$("#edit-contact-jid").text("Select a buddy in the list above to update."),$("#edit-contact-name").val(""),$("#edit-contact-form input").hide(),$("#edit-contact-form .buttons").hide(),!1},a.prototype.updateContact=function(){var a;return this.toggleForm("#edit-contact-form"),a={jid:this.currentContact,name:$("#edit-contact-name").val(),groups:this.session.roster[this.currentContact].groups},this.session.updateContact(a),!1},a.prototype.toggleForm=function(a,b){return a=$(a),$("form.overlay").each(function(){if(this.id!==a.attr("id"))return $(this).hide()}),a.is(":hidden")?(b&&b(),a.fadeIn(100)):a.fadeOut(100,function(){a[0].reset();if(b)return b()})},a.prototype.draw=function(){var a,b;if(!this.session.connected()){window.location.hash="";return}return $("body").attr("id","chat-page"),$("#container").hide().empty(),$('<div id="alpha" class="sidebar column y-fill">\n <h2>Buddies <div id="search-roster-icon"></div></h2>\n <div id="search-roster-form"></div>\n <ul id="roster" class="selectable scroll y-fill"></ul>\n <div id="alpha-controls" class="controls">\n <div id="add-contact"></div>\n <div id="remove-contact"></div>\n <div id="edit-contact"></div>\n </div>\n <form id="add-contact-form" class="overlay" style="display:none;">\n <h2>Add Buddy</h2>\n <input id="add-contact-jid" type="email" maxlength="1024" placeholder="Account name"/>\n <input id="add-contact-name" type="text" maxlength="1024" placeholder="Real name"/>\n <fieldset class="buttons">\n <input id="add-contact-cancel" type="button" value="Cancel"/>\n <input id="add-contact-ok" type="submit" value="Add"/>\n </fieldset>\n </form>\n <form id="remove-contact-form" class="overlay" style="display:none;">\n <h2>Remove Buddy</h2>\n <p id="remove-contact-msg">Select a buddy in the list above to remove.</p>\n <fieldset class="buttons" style="display:none;">\n <input id="remove-contact-cancel" type="button" value="Cancel"/>\n <input id="remove-contact-ok" type="submit" value="Remove"/>\n </fieldset>\n </form>\n <form id="edit-contact-form" class="overlay" style="display:none;">\n <h2>Update Profile</h2>\n <p id="edit-contact-jid">Select a buddy in the list above to update.</p>\n <input id="edit-contact-name" type="text" maxlength="1024" placeholder="Real name" style="display:none;"/>\n <fieldset class="buttons" style="display:none;">\n <input id="edit-contact-cancel" type="button" value="Cancel"/>\n <input id="edit-contact-ok" type="submit" value="Save"/>\n </fieldset>\n </form>\n</div>\n<div id="beta" class="primary column x-fill y-fill">\n <h2 id="chat-title">Select a buddy to chat</h2>\n <ul id="messages" class="scroll y-fill"></ul>\n <form id="message-form">\n <input id="message" name="message" type="text" maxlength="1024" placeholder="Type a message and press enter to send"/>\n </form>\n</div>\n<div id="charlie" class="sidebar column y-fill">\n <h2>Notifications</h2>\n <ul id="notifications" class="scroll y-fill"></ul>\n <div id="charlie-controls" class="controls">\n <div id="clear-notices"></div>\n </div>\n</div>').appendTo("#container"),this.roster(),new Button("#clear-notices",ICONS.no),new Button("#add-contact",ICONS.plus),new Button("#remove-contact",ICONS.minus),new Button("#edit-contact",ICONS.user),$("#message").focus(function(){return $("form.overlay").fadeOut()}),$("#message-form").submit(__bind(function(){return this.send()},this)),$("#clear-notices").click(function(){return $("#notifications li").fadeOut(200)}),$("#add-contact").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact").click(__bind(function(){return this.toggleForm("#edit-contact-form",__bind(function(){if(this.currentContact)return $("#edit-contact-jid").text(this.currentContact),$("#edit-contact-name").val(this.session.roster[this.currentContact].name)},this))},this)),$("#add-contact-cancel").click(__bind(function(){return this.toggleForm("#add-contact-form")},this)),$("#remove-contact-cancel").click(__bind(function(){return this.toggleForm("#remove-contact-form")},this)),$("#edit-contact-cancel").click(__bind(function(){return this.toggleForm("#edit-contact-form")},this)),$("#add-contact-form").submit(__bind(function(){return this.addContact()},this)),$("#remove-contact-form").submit(__bind(function(){return this.removeContact()},this)),$("#edit-contact-form").submit(__bind(function(){return this.updateContact()},this)),$("#container").fadeIn(200),b=this.resize(),a=function(){return b.resize(),b.resize()},new Filter({list:"#roster",icon:"#search-roster-icon",form:"#search-roster-form",attrs:["data-jid","data-name"],open:a,close:a})},a.prototype.resize=function(){var a,b,c,d,e;return a=$("#alpha"),b=$("#beta"),c=$("#charlie"),e=$("#message"),d=$("#message-form"),new Layout(function(){return c.css("left",a.width()+b.width()),e.width(d.width()-32)})},a}(),$(function(){var a,b,c,d,e,f;f=new Session,d=new NavBar(f),d.draw(),a={Messages:ICONS.chat,Logout:ICONS.power};for(c in a)b=a[c],d.addButton(c,b);return e={"/messages":new ChatPage(f),"/logout":new LogoutPage(f),"default":new LoginPage(f,"/messages/")},(new Router(e)).draw(),d.select($("#nav-link-messages").parent())})
@@ -55,11 +55,6 @@
55
55
  bottom: 0;
56
56
  width: 100%;
57
57
  }
58
- #chat-page input[type="text"]:focus,
59
- #chat-page input[type="email"]:focus {
60
- -webkit-box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.6);
61
- box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.6);
62
- }
63
58
  #chat-page #message {
64
59
  display: block;
65
60
  position: relative;
@@ -111,10 +106,10 @@
111
106
  line-height: 11px;
112
107
  }
113
108
  #chat-page #roster .unread {
114
- background: #4693FF;
115
- background: -moz-linear-gradient(#4693FF, #015de6);
116
- background: -o-linear-gradient(#4693FF, #015de6);
117
- background: -webkit-gradient(linear, left top, left bottom, from(#4693FF), to(#015de6));
109
+ background: #319be7;
110
+ background: -moz-linear-gradient(#319be7, #1b78d9);
111
+ background: -o-linear-gradient(#319be7, #1b78d9);
112
+ background: -webkit-gradient(linear, left top, left bottom, from(#319be7), to(#1b78d9));
118
113
  border-radius: 30px;
119
114
  color: #fff;
120
115
  display: inline-block;