overleaf/services/chat/public/coffee/views/chatWindowView.coffee
2014-08-15 10:50:36 +01:00

219 lines
6.9 KiB
CoffeeScript

define [
"libs/underscore"
"libs/backbone"
"views/userMessageBlockView"
"views/timeMessageBlockView"
], (_, Backbone, UserMessageBlockView, TimeMessageBlockView) ->
FIVE_MINS = 5 * 60 * 1000
ONE_HOUR = 60 * 60 * 1000
TWELVE_HOURS = ONE_HOUR * 12
ONE_DAY = ONE_HOUR * 24
ChatWindowView = Backbone.View.extend
events:
"keydown textarea" : "_onTextAreaKeyDown"
"click .js-load-older-messages" : "_loadOlderMessages"
"click .js-minimize-toggle" : "_toggleMinimizeState"
"click h3" : "_toggleMinimizeState"
"click .js-new-message-alert" : "_toggleMinimizeState"
"click" : "_removeNotification"
initialize: () ->
@template = $("#chatWindowTemplate").html()
@chat = @options.chat
@room = @options.room
@listenTo @room.get("messages"), "add", (model, collection) -> @_onNewMessage(model, collection)
@listenTo @room.get("messages"), "noMoreMessages", () -> @$(".js-loading").hide()
@listenTo @room.get("connectedUsers"), "add", (user, collection) -> @_renderConnectedUsers()
@listenTo @room.get("connectedUsers"), "remove", (user, collection) -> @_renderConnectedUsers()
@listenTo @room.get("connectedUsers"), "change", (user, collection) -> @_renderConnectedUsers()
@listenTo @room, "joined", -> @_onJoin()
@listenTo @room, "disconnected", -> @_onDisconnect()
@listenTo @room, "afterMessagesPreloaded", -> @_scrollToBottomOfMessages()
render: () ->
@setElement($(@template))
$(document.body).append(@$el)
@_renderConnectedUsers()
@_initializeMinimizedState()
_onJoin: () ->
if !@rendered?
@render()
@rendered = true
@$el.removeClass("disconnected")
@$("textarea").removeAttr("disabled")
_onDisconnect: () ->
@$el.addClass("disconnected")
@$("textarea").attr("disabled", "disabled")
_onNewMessage: (message, collection) ->
@_renderMessage(message, collection)
@_notifyAboutNewMessage(message)
_renderMessage: (message, collection) ->
@messageBlocks ||= []
scrollEl = @$(".sent-message-area")
isOldestMessage = (message, collection)->
collection.indexOf(message) == 0
ismessageFromNewUser = (messageView, message)->
!messageView? or messageView.user != message.get("user")
isTimeForNewBlockBackwards = (message, previousUserMessageBlockView)->
if !message? or !previousUserMessageBlockView?
return true
timeSinceMessageWasSent = new Date().getTime() - message.get("timestamp")
if timeSinceMessageWasSent < ONE_HOUR
timeBlockSize = FIVE_MINS
else if timeSinceMessageWasSent > ONE_HOUR and timeSinceMessageWasSent < (ONE_DAY + TWELVE_HOURS)
timeBlockSize = ONE_HOUR
else
timeBlockSize = ONE_DAY
timeSinceLastPrinted = previousUserMessageBlockView.getTime() - message.get("timestamp")
if timeSinceLastPrinted > timeBlockSize
return true
else
return false
isTimeForNewBlock = (message, previousUserMessageBlockView)->
(message.get("timestamp") - previousUserMessageBlockView.getTime()) > FIVE_MINS
if isOldestMessage(message, collection)
oldScrollTopFromBottom = scrollEl[0].scrollHeight - scrollEl.scrollTop()
userMessageBlockView = @messageBlocks[0]
if ismessageFromNewUser(userMessageBlockView, message) or isTimeForNewBlockBackwards(message, userMessageBlockView)
userMessageBlockView = new UserMessageBlockView(user: message.get("user"))
@$(".sent-messages").prepend(userMessageBlockView.$el)
@messageBlocks.unshift userMessageBlockView
userMessageBlockView.prependMessage(message)
scrollEl.scrollTop(scrollEl[0].scrollHeight - oldScrollTopFromBottom)
else
oldScrollBottom = @_getScrollBottom()
userMessageBlockView = @messageBlocks[@messageBlocks.length - 1]
if ismessageFromNewUser(userMessageBlockView, message) or isTimeForNewBlock(message, userMessageBlockView)
userMessageBlockView = new UserMessageBlockView(user: message.get("user"))
@$(".sent-messages").append(userMessageBlockView.$el)
@messageBlocks.push userMessageBlockView
userMessageBlockView.appendMessage(message)
if oldScrollBottom <= 0
@_scrollToBottomOfMessages()
_renderConnectedUsers: () ->
users = @room.get("connectedUsers")
names = users
.reject((user) => user == @chat.user)
.map((user) -> "#{user.get("first_name")} #{user.get("last_name")}")
if names.length == 0
text = "No one else is online :("
else if names.length == 1
text = "#{names[0]} is also online"
else
text = "#{names.slice(0, -1).join(", ")} and #{names[names.length - 1]} are also online"
@$(".js-connected-users").text(text)
@_resizeSentMessageArea()
_resizeSentMessageArea: () ->
marginTop = @$(".js-header").outerHeight() + @$(".js-connected-users").outerHeight()
@$(".js-sent-message-area").css({
top: marginTop + "px"
})
_getScrollBottom: () ->
scrollEl = @$(".sent-message-area")
return scrollEl[0].scrollHeight - scrollEl.scrollTop() - scrollEl.innerHeight()
_scrollToBottomOfMessages: () ->
scrollEl = @$(".sent-message-area")
doScroll = ->
return scrollEl.scrollTop(scrollEl[0].scrollHeight - scrollEl.innerHeight())
MathJax.Hub.Queue(["Typeset", doScroll])
_notifyAboutNewMessage: (message) ->
isMessageNewToUser = message.get("user") != @chat.user and !message.get("preloaded")
isTextAreaFocused = @$("textarea").is(":focus")
if !isTextAreaFocused and isMessageNewToUser
@unseenMessages ||= 0
@unseenMessages += 1
@$el.addClass("new-messages")
@$(".new-message-alert").text(@unseenMessages)
_removeNotification: () ->
@unseenMessages = 0
@$el.removeClass("new-messages")
@$(".new-message-alert").text("")
_onTextAreaKeyDown: (e) ->
if e.keyCode == 13 # Enter
e.preventDefault()
message = @$("textarea").val()
@$("textarea").val("")
@_sendMessage(message)
_loadOlderMessages: (e) ->
e.preventDefault()
@room.get("messages").fetchMoreMessages()
_sendMessage: (content) ->
@room.sendMessage(content)
isMinimized: () ->
minimized = $.localStorage "chat.rooms.project-chat.minimized"
if !minimized?
minimized = false
return minimized
_setMinimizedState: (state) ->
$.localStorage "chat.rooms.project-chat.minimized", state
_initializeMinimizedState: () ->
minimized = @isMinimized()
if minimized
@_minimize(false)
_toggleMinimizeState: (e) ->
e.preventDefault()
minimized = @isMinimized()
if !minimized
@_setMinimizedState(true)
@_minimize()
else
@_setMinimizedState(false)
@_unminimize()
_minimize: (animate = true) ->
@$(".new-message-area").hide()
@$(".js-connected-users").hide()
@$el.addClass("minimized")
if animate
@$el.animate height: 20, width: 80
else
@$el.css height: 20, width: 80
_unminimize: () ->
@$(".new-message-area").show()
@$(".js-connected-users").show()
@$el.removeClass("minimized")
@$el.animate height: 260, width: 220, () =>
@_resizeSentMessageArea()
@_scrollToBottomOfMessages()