This repository was archived by the owner on Oct 19, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathchat_app_source.html
More file actions
172 lines (146 loc) · 5.64 KB
/
chat_app_source.html
File metadata and controls
172 lines (146 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React</title>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
<script src="https://rawgit.com/reactrb/reactrb-express/master/reactrb-express.js"></script>
<script src="http://ruby-hyperloop.io/javascripts/test_chat_service.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<style type="text/css">
/* most styles will come from bootstrap, but we will be adding a
few extra styles here */
</style>
<script type="text/ruby">
class App < React::Component::Base
before_mount do
@chat_service = ChatService.new do | messages |
state.messages! ((state.messages || []) + messages)
puts "state messages updated. state.messages: #{state.messages}"
end
end
def render
div do
Nav login: method(:login).to_proc
if online?
Messages messages: state.messages
InputBox chat_service: @chat_service
end
end
end
def login(user_name)
@chat_service.login(user_name)
end
def online?
state.messages
end
end
class Nav < React::Component::Base
param :login, type: Proc
before_mount do
state.current_user_name! nil
state.user_name_input! ""
end
def render
div.navbar.navbar_inverse.navbar_fixed_top do
div.container do
div.collapse.navbar_collapse(id: "navbar") do
form.navbar_form.navbar_left(role: :search) do
div.form_group do
input.form_control(type: :text, value: state.user_name_input, placeholder: "Enter Your Handle"
).on(:change) do |e|
state.user_name_input! e.target.value
end
button.btn.btn_default(type: :button) { "login!" }.on(:click) do
login!
end if valid_new_input?
end
end
end
end
end
end
def valid_new_input?
state.user_name_input.present? && state.user_name_input != state.current_user_name
end
def login!
state.current_user_name! state.user_name_input
params.login(state.user_name_input)
end
end
class Messages < React::Component::Base
param :messages, type: [Hash]
def render
div.container do # add the bootstrap .container class here.
params.messages.each do |message|
Message message: message
end
end
end
end
class Message < React::Component::Base
param :message, type: Hash
after_mount :scroll_to_bottom
after_update :scroll_to_bottom
def render
div.row.alternating.message do
div.col_sm_2 { params.message[:from] }
FormattedDiv class: "col-sm-8", markdown: params.message[:message]
div.col_sm_2 { Time.at(params.message[:time]).to_s }
end
end
def scroll_to_bottom
Element['html, body'].animate({scrollTop: Element[Document].height}, :slow)
end
end
class InputBox < React::Component::Base
param :chat_service, type: ChatService
before_mount { state.composition! "" }
def render
div.row.form_group.input_box.navbar.navbar_inverse.navbar_fixed_bottom do
div.col_sm_1.white {"Say: "}
textarea.col_sm_5(rows: rows,
value: state.composition,
placeholder: "Ctrl-Enter to post"
).on(:change) do |e|
state.composition! e.target.value
end.on(:key_down) do |e|
send_message if is_send_key?(e)
end
FormattedDiv class: "col-sm-5 white", markdown: state.composition
end
end
def rows
[state.composition.count("\n") + 1,20].min
end
def is_send_key?(e)
#(e.char_code == 13 || e.key_code == 13)
(e.char_code == 13 || e.key_code == 13) && (e.meta_key || e.ctrl_key)
end
def send_message
params.chat_service.send(
message: state.composition!(""),
time: Time.now.to_i,
from: params.chat_service.id
)
end
end
class FormattedDiv < React::Component::Base
param :markdown, type: String
collect_other_params_as :attributes
def render
div(params.attributes) do # send whatever class is specified on to the outer div
div({dangerously_set_inner_HTML: { __html: `marked(#{params.markdown}, {sanitize: true })`}})
end
end
end
</script>
</head>
<body>
<!-- Tell inline reactive ruby to mount App here -->
<div data-reactrb-mount="App"></div>
</body>
</html>