-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathchat.coffee
208 lines (172 loc) · 5.4 KB
/
chat.coffee
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
InputModule = require 'input'
class exports.Chat
defaults =
fontSize: 24
lineHeight: 36
padding: 20
borderRadius: 20
maxWidth: Screen.width * 0.6
avatarSize: 60
avatarBorderRadius: 30
inputBorderColor: '#ccc'
inputHeight: 80
placeholder: 'Start chatting'
defaultUserId: 1
authorTextColor: '#999'
bubbleColor:
right: '#4080FF'
left: '#eee'
bubbleText:
right: 'white'
left: 'black'
data: [
{
author: 1
message: 'Lorem ipsum dolor sit amet, ei has impetus vituperata adversarium, nihil populo semper eu ius, an eam vero sensibus.'
}
]
users: [
{
id: 1
name: 'Ningxia'
avatar: 'ningxia.jpg'
}
]
constructor: (options) ->
if options == undefined then options = {}
options = _.defaults options, defaults
@options = options
@_group = 0
@commentsScroll = new ScrollComponent
name: 'comments'
backgroundColor: null
width: Screen.width
height: Screen.height - @options.inputHeight
mouseWheelEnabled: true
scrollHorizontal: false
@commentsScroll.contentInset =
top: @options.padding
@renderComment = (comment, align) =>
# Calcuate the message size
@_messageSize = Utils.textSize comment.message,
{'padding': "#{@options.padding}px"},
{width: @options.maxWidth}
@_leftPadding = @options.padding * 2 + @options.avatarSize
# Find the author
@_author = _.find @options.users, {id: comment.author}
# Find comments by the same author
# Only works on left comments so far, need to do for right
@_commentIndex = _.findIndex @options.data, comment
@_previousComment = @_nextComment = @options.data[@_commentIndex - 1]
@_nextComment = @options.data[@_commentIndex + 1]
@_sameNextAuthor = if @_nextComment and @_nextComment.author is comment.author then true else false
@_samePreviousAuthor = if @_previousComment and @_previousComment.author is comment.author then true else false
if @_samePreviousAuthor or @_sameNextAuthor
@_group = @_group + 1
@_messageMargin = if @_sameNextAuthor and align is 'left' then @options.lineHeight * 0.25 else @options.lineHeight * 2
# Construct the comment
@comment = new Layer
parent: @commentsScroll.content
name: 'comment'
backgroundColor: null
width: Screen.width
height: @_messageSize.height + @_messageMargin
unless @_samePreviousAuthor
@author = new Layer
name: 'comment:author'
html: @_author.name
parent: @comment
x: if align is 'right' then Align.right(-@options.padding) else @_leftPadding
width: @comment.width
color: @options.authorTextColor
backgroundColor: null
style:
'font-weight': 'bold'
'font-size': '90%'
'text-align': align
@message = new Layer
name: 'comment:message'
parent: @comment
html: comment.message
height: @_messageSize.height
y: @options.lineHeight
backgroundColor: @options.bubbleColor[align]
color: @options.bubbleText[align]
borderRadius: @options.borderRadius
style:
'padding': "#{@options.padding}px"
'width': 'auto'
'max-width': "#{@_messageSize.width}px"
'text-align': align
# Special stuff for alignment
if align is 'right'
@_width = parseInt @message.computedStyle()['width']
@message.x = Screen.width - @_width - @options.padding
else
# Avatar
@.message.x = @_leftPadding
unless @_sameNextAuthor
@avatar = new Layer
parent: @comment
name: 'comment:avatar'
size: @options.avatarSize
borderRadius: @options.avatarBorderRadius
image: "images/#{@_author.avatar}"
x: @options.padding
y: Align.bottom(-@options.padding * 2)
# Grouped comments border
if @_samePreviousAuthor and @_sameNextAuthor
@message.style =
"border-top-#{align}-radius": '3px'
"border-bottom-#{align}-radius": '3px'
if @_group is 1
@message.style = "border-bottom-#{align}-radius": '3px'
if @_group > 1 and !@_sameNextAuthor
@message.style = "border-top-#{align}-radius": '3px'
# Recalcuate position
@reflow()
@reflow = () =>
@commentsHeight = 0
@comments = @commentsScroll.content.children
# Loop through all the comments
for comment, i in @comments
commentsHeight = @commentsHeight + comment.height
@yOffset = 0
# Add up the height of the sibling layers to the left of the current layer
for layer in _.take(@comments, i)
@yOffset = @yOffset + layer.height
# Set the current comment position to the height of left siblings
comment.y = @yOffset
# Scroll stuff
@commentsScroll.updateContent()
@commentsScroll.scrollToLayer @comments[@comments.length - 1]
# Draw everything
_.map @options.data, (comment) =>
@renderComment(comment, 'left')
# New commpents
@inputWrapper = new Layer
name: 'input'
backgroundColor: null
height: @options.inputHeight
width: Screen.width
y: Align.bottom
style:
'border-top': "1px solid #{@options.inputBorderColor}"
@input = new InputModule.Input
name: 'input:field'
parent: @inputWrapper
width: Screen.width
placeholder: @options.placeholder
virtualKeyboard: false
createComment = (value) =>
newComment =
author: @options.defaultUserId
message: value
@renderComment newComment, 'right'
@input.on 'keyup', (event) ->
# Add new comments
if event.which is 13
createComment(@value)
@value = ''
@input.form.addEventListener 'submit', (event) ->
event.preventDefault()