The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/client/views/app/room.coffee

646 lines
18 KiB

# @TODO bug com o botão para "rolar até o fim" (novas mensagens) quando há uma mensagem com texto que gere rolagem horizontal
Template.room.helpers
favorite: ->
sub = ChatSubscription.findOne { rid: this._id }, { fields: { f: 1 } }
return 'icon-star favorite-room' if sub?.f? and sub.f
return 'icon-star-empty'
subscribed: ->
return ChatSubscription.find({ rid: this._id }).count() > 0
messagesHistory: ->
return ChatMessage.find { rid: this._id, t: { '$ne': 't' } }, { sort: { ts: 1 } }
hasMore: ->
return RoomHistoryManager.hasMore this._id
isLoading: ->
return RoomHistoryManager.isLoading this._id
windowId: ->
return "chat-window-#{this._id}"
uploading: ->
return Session.get 'uploading'
usersTyping: ->
users = MsgTyping.get @_id
if users.length is 0
return
if users.length is 1
return {
multi: false
selfTyping: MsgTyping.selfTyping.get()
users: users[0]
}
# usernames = _.map messages, (message) -> return message.u.username
last = users.pop()
if users.length > 4
last = t('others')
# else
usernames = users.join(', ')
usernames = [usernames, last]
return {
multi: true
selfTyping: MsgTyping.selfTyping.get()
users: usernames.join " #{t 'and'} "
}
roomName: ->
roomData = Session.get('roomData' + this._id)
return '' unless roomData
if roomData.t is 'd'
return ChatSubscription.findOne({ rid: this._id }, { fields: { name: 1 } })?.name
else
return roomData.name
roomIcon: ->
roomData = Session.get('roomData' + this._id)
return '' unless roomData?.t
switch roomData.t
when 'd' then return 'icon-at'
when 'c' then return 'icon-hash'
when 'p' then return 'icon-lock'
userStatus: ->
roomData = Session.get('roomData' + this._id)
return {} unless roomData
if roomData.t is 'd'
username = _.without roomData.usernames, Meteor.user().username
return Session.get('user_' + username + '_status') || 'offline'
else
return 'offline'
autocompleteSettingsRoomSearch: ->
return {
limit: 10
# inputDelay: 300
rules: [
{
collection: 'UserAndRoom'
subscription: 'roomSearch'
field: 'name'
template: Template.roomSearch
noMatchTemplate: Template.roomSearchEmpty
matchAll: true
filter: { uid: { $ne: Meteor.userId() } }
sort: 'name'
}
]
}
isChannel: ->
roomData = Session.get('roomData' + this._id)
return '' unless roomData
return roomData.t is 'c'
canEditName: ->
roomData = Session.get('roomData' + this._id)
return '' unless roomData
if roomData.t in ['c', 'p']
return RocketChat.authz.hasAtLeastOnePermission('edit-room', this._id)
else
return ''
canDirectMessage: ->
return Meteor.user()?.username isnt this.username
roomNameEdit: ->
return Session.get('roomData' + this._id)?.name
editingTitle: ->
return 'hidden' if Session.get('editRoomTitle')
showEditingTitle: ->
return 'hidden' if not Session.get('editRoomTitle')
flexOpened: ->
return 'opened' if RocketChat.TabBar.isFlexOpen()
arrowPosition: ->
return 'left' unless RocketChat.TabBar.isFlexOpen()
phoneNumber: ->
return '' unless this.phoneNumber
if this.phoneNumber.length > 10
return "(#{this.phoneNumber.substr(0,2)}) #{this.phoneNumber.substr(2,5)}-#{this.phoneNumber.substr(7)}"
else
return "(#{this.phoneNumber.substr(0,2)}) #{this.phoneNumber.substr(2,4)}-#{this.phoneNumber.substr(6)}"
userActiveByUsername: (username) ->
status = Session.get 'user_' + username + '_status'
if status in ['online', 'away', 'busy']
return {username: username, status: status}
return
seeAll: ->
if Template.instance().showUsersOffline.get()
return t('See_only_online')
else
return t('See_all')
getPupupConfig: ->
template = Template.instance()
return {
getInput: ->
return template.find('.input-message')
}
remoteVideoUrl: ->
return Session.get('remoteVideoUrl')
selfVideoUrl: ->
return Session.get('selfVideoUrl')
videoActive: ->
return (Session.get('remoteVideoUrl') || Session.get('selfVideoUrl'))
remoteMonitoring: ->
return (webrtc?.stackid? && (webrtc.stackid == 'webrtc-ib'))
flexOpenedRTC1: ->
return 'layout1' if Session.equals('flexOpenedRTC1', true)
flexOpenedRTC2: ->
return 'layout2' if Session.equals('flexOpenedRTC2', true)
rtcLayout1: ->
return (Session.get('rtcLayoutmode') == 1 ? true: false);
rtcLayout2: ->
return (Session.get('rtcLayoutmode') == 2 ? true: false);
rtcLayout3: ->
return (Session.get('rtcLayoutmode') == 3 ? true: false);
noRtcLayout: ->
return (!Session.get('rtcLayoutmode') || (Session.get('rtcLayoutmode') == 0) ? true: false);
maxMessageLength: ->
return RocketChat.settings.get('Message_MaxAllowedSize')
utc: ->
if @utcOffset?
return "UTC #{@utcOffset}"
phoneNumber: ->
return '' unless @phoneNumber
if @phoneNumber.length > 10
return "(#{@phoneNumber.substr(0,2)}) #{@phoneNumber.substr(2,5)}-#{@phoneNumber.substr(7)}"
else
return "(#{@phoneNumber.substr(0,2)}) #{@phoneNumber.substr(2,4)}-#{@phoneNumber.substr(6)}"
lastLogin: ->
if @lastLogin
return moment(@lastLogin).format('LLL')
canJoin: ->
return !! ChatRoom.findOne { _id: @_id, t: 'c' }
canRecordAudio: ->
return navigator.getUserMedia? or navigator.webkitGetUserMedia?
roomManager: ->
room = ChatRoom.findOne(this._id, { reactive: false })
return RoomManager.openedRooms[room.t + room.name]
unreadCount: ->
return RoomHistoryManager.getRoom(@_id).unreadNotLoaded.get() + Template.instance().unreadCount.get()
formatUnreadSince: ->
room = ChatRoom.findOne(this._id, { reactive: false })
room = RoomManager.openedRooms[room.t + room.name]
date = room?.unreadSince.get()
if not date? then return
return moment(date).calendar(null, {sameDay: 'LT'})
flexTemplate: ->
return RocketChat.TabBar.getTemplate()
flexData: ->
return RocketChat.TabBar.getData()
adminClass: ->
return 'admin' if Meteor.user()?.admin is true
Template.room.events
"touchstart .message": (e, t) ->
message = this._arguments[1]
doLongTouch = ->
mobileMessageMenu.show(message, t)
t.touchtime = Meteor.setTimeout doLongTouch, 500
"touchend .message": (e, t) ->
Meteor.clearTimeout t.touchtime
"touchmove .message": (e, t) ->
Meteor.clearTimeout t.touchtime
"touchcancel .message": (e, t) ->
Meteor.clearTimeout t.touchtime
"click .upload-progress-item > a": ->
Session.set "uploading-cancel-#{this.id}", true
"click .unread-bar > a": ->
readMessage.readNow(true)
"click .flex-tab .more": (event, t) ->
if RocketChat.TabBar.isFlexOpen()
Session.set('rtcLayoutmode', 0)
RocketChat.TabBar.closeFlex()
t.searchResult.set undefined
else
RocketChat.TabBar.openFlex()
"click .flex-tab .video-remote" : (e) ->
if RocketChat.TabBar.isFlexOpen()
if (!Session.get('rtcLayoutmode'))
Session.set('rtcLayoutmode', 1)
else
t = Session.get('rtcLayoutmode')
t = (t + 1) % 4
console.log 'setting rtcLayoutmode to ' + t if window.rocketDebug
Session.set('rtcLayoutmode', t)
"click .flex-tab .video-self" : (e) ->
if (Session.get('rtcLayoutmode') == 3)
console.log 'video-self clicked in layout3' if window.rocketDebug
i = document.getElementById("fullscreendiv")
if i.requestFullscreen
i.requestFullscreen()
else
if i.webkitRequestFullscreen
i.webkitRequestFullscreen()
else
if i.mozRequestFullScreen
i.mozRequestFullScreen()
else
if i.msRequestFullscreen
i.msRequestFullscreen()
'click .toggle-favorite': (event) ->
event.stopPropagation()
event.preventDefault()
Meteor.call 'toogleFavorite', @_id, !$('i', event.currentTarget).hasClass('favorite-room')
'click .join': (event) ->
event.stopPropagation()
event.preventDefault()
Meteor.call 'joinRoom', @_id
'focus .input-message': (event) ->
KonchatNotification.removeRoomNotification @_id
'keyup .input-message': (event) ->
Template.instance().chatMessages.keyup(@_id, event, Template.instance())
'paste .input-message': (e) ->
if not e.originalEvent.clipboardData?
return
items = e.originalEvent.clipboardData.items
files = []
for item in items
if item.kind is 'file' and item.type.indexOf('image/') isnt -1
e.preventDefault()
files.push
file: item.getAsFile()
name: 'Clipboard'
fileUpload files
'keydown .input-message': (event) ->
Template.instance().chatMessages.keydown(@_id, event, Template.instance())
'click .message-form .icon-paper-plane': (event) ->
input = $(event.currentTarget).siblings("textarea")
Template.instance().chatMessages.send(this._id, input.get(0))
event.preventDefault()
event.stopPropagation()
input.focus()
input.get(0).updateAutogrow()
'click .add-user': (event) ->
toggleAddUser()
'click .edit-room-title': (event) ->
event.preventDefault()
Session.set('editRoomTitle', true)
$(".fixed-title").addClass "visible"
Meteor.setTimeout ->
$('#room-title-field').focus().select()
, 10
'keydown #user-add-search': (event) ->
if event.keyCode is 27 # esc
toggleAddUser()
'keydown #room-title-field': (event) ->
if event.keyCode is 27 # esc
Session.set('editRoomTitle', false)
else if event.keyCode is 13 # enter
renameRoom @_id, $(event.currentTarget).val()
'blur #room-title-field': (event) ->
# TUDO: create a configuration to select the desired behaviour
# renameRoom this._id, $(event.currentTarget).val()
Session.set('editRoomTitle', false)
$(".fixed-title").removeClass "visible"
"click .flex-tab .user-image > a" : (e) ->
RocketChat.TabBar.openFlex()
Session.set('showUserInfo', $(e.currentTarget).data('username'))
'click .user-card-message': (e) ->
roomData = Session.get('roomData' + this._arguments[1].rid)
if roomData.t in ['c', 'p']
# Session.set('flexOpened', true)
Session.set('showUserInfo', $(e.currentTarget).data('username'))
# else
# Session.set('flexOpened', true)
RocketChat.TabBar.setTemplate 'membersList'
'autocompleteselect #user-add-search': (event, template, doc) ->
roomData = Session.get('roomData' + Session.get('openedRoom'))
if roomData.t is 'd'
Meteor.call 'createGroupRoom', roomData.usernames, doc.username, (error, result) ->
if error
return Errors.throw error.reason
if result?.rid?
$('#user-add-search').val('')
else if roomData.t in ['c', 'p']
Meteor.call 'addUserToRoom', { rid: roomData._id, username: doc.username }, (error, result) ->
if error
return Errors.throw error.reason
$('#user-add-search').val('')
toggleAddUser()
'scroll .wrapper': _.throttle (e, instance) ->
if RoomHistoryManager.hasMore(@_id) is true and RoomHistoryManager.isLoading(@_id) is false
if e.target.scrollTop is 0
RoomHistoryManager.getMore(@_id)
, 200
'click .load-more > a': ->
RoomHistoryManager.getMore(@_id)
'click .new-message': (e) ->
Template.instance().atBottom = true
Template.instance().find('.input-message').focus()
'click .see-all': (e, instance) ->
instance.showUsersOffline.set(!instance.showUsersOffline.get())
'click .message-cog': (e) ->
message_id = $(e.currentTarget).closest('.message').attr('id')
$('.message-dropdown:visible').hide()
$(".messages-box \##{message_id} .message-dropdown").show()
'click .message-dropdown-close': ->
$('.message-dropdown:visible').hide()
"click .editing-commands-cancel > a": (e) ->
Template.instance().chatMessages.clearEditing()
"click .editing-commands-save > a": (e) ->
chatMessages = Template.instance().chatMessages
chatMessages.send(@_id, chatMessages.input)
"click .mention-link": (e) ->
channel = $(e.currentTarget).data('channel')
if channel?
FlowRouter.go 'channel', {name: channel}
return
RocketChat.TabBar.openFlex()
Session.set('showUserInfo', $(e.currentTarget).data('username'))
'click .image-to-download': (event) ->
ChatMessage.update {_id: this._arguments[1]._id, 'urls.url': $(event.currentTarget).data('url')}, {$set: {'urls.$.downloadImages': true}}
'click .pin-message': (event) ->
message = @_arguments[1]
instance = Template.instance()
if message.pinned
instance.chatMessages.unpinMsg(message)
else
instance.chatMessages.pinMsg(message)
'dragenter .dropzone': (e) ->
e.currentTarget.classList.add 'over'
'dragleave .dropzone-overlay': (e) ->
e.currentTarget.parentNode.classList.remove 'over'
'dropped .dropzone-overlay': (event) ->
event.currentTarget.parentNode.classList.remove 'over'
e = event.originalEvent or event
files = e.target.files
if not files or files.length is 0
files = e.dataTransfer?.files or []
filesToUpload = []
for file in files
filesToUpload.push
file: file
name: file.name
fileUpload filesToUpload
'change .message-form input[type=file]': (event, template) ->
e = event.originalEvent or event
files = e.target.files
if not files or files.length is 0
files = e.dataTransfer?.files or []
filesToUpload = []
for file in files
filesToUpload.push
file: file
name: file.name
fileUpload filesToUpload
'click .message-form .mic': (e, t) ->
AudioRecorder.start ->
t.$('.stop-mic').removeClass('hidden')
t.$('.mic').addClass('hidden')
'click .message-form .stop-mic': (e, t) ->
AudioRecorder.stop (blob) ->
fileUpload [{
file: blob
type: 'audio'
name: 'Audio record'
}]
t.$('.stop-mic').addClass('hidden')
t.$('.mic').removeClass('hidden')
'click .deactivate': ->
username = Session.get('showUserInfo')
user = Meteor.users.findOne { username: String(username) }
Meteor.call 'setUserActiveStatus', user?._id, false, (error, result) ->
if result
toastr.success t('User_has_been_deactivated')
if error
toastr.error error.reason
'click .activate': ->
username = Session.get('showUserInfo')
user = Meteor.users.findOne { username: String(username) }
Meteor.call 'setUserActiveStatus', user?._id, true, (error, result) ->
if result
toastr.success t('User_has_been_activated')
if error
toastr.error error.reason
Template.room.onCreated ->
# this.scrollOnBottom = true
# this.typing = new msgTyping this.data._id
this.showUsersOffline = new ReactiveVar false
this.atBottom = true
this.unreadCount = new ReactiveVar 0
self = @
@autorun ->
self.subscribe 'fullUserData', Session.get('showUserInfo'), 1
for button in RocketChat.MessageAction.getButtons()
if _.isFunction button.action
evt = {}
evt["click .#{button.id}"] = button.action
Template.room.events evt
Template.room.onDestroyed ->
RocketChat.TabBar.resetButtons()
Template.room.onRendered ->
this.chatMessages = new ChatMessages
this.chatMessages.init(this.firstNode)
# ScrollListener.init()
wrapper = this.find('.wrapper')
newMessage = this.find(".new-message")
template = this
wrapperOffset = $('.messages-box > .wrapper').offset()
onscroll = _.throttle ->
template.atBottom = wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight
, 200
updateUnreadCount = _.throttle ->
firstMessageOnScreen = document.elementFromPoint(wrapperOffset.left+1, wrapperOffset.top+50)
if firstMessageOnScreen?.id?
firstMessage = ChatMessage.findOne firstMessageOnScreen.id
if firstMessage?
subscription = ChatSubscription.findOne rid: template.data._id
template.unreadCount.set ChatMessage.find({rid: template.data._id, ts: {$lt: firstMessage.ts, $gt: subscription.ls}}).count()
else
template.unreadCount.set 0
, 300
Meteor.setInterval ->
if template.atBottom
wrapper.scrollTop = wrapper.scrollHeight - wrapper.clientHeight
newMessage.className = "new-message not"
, 100
wrapper.addEventListener 'touchstart', ->
template.atBottom = false
wrapper.addEventListener 'touchend', ->
onscroll()
readMessage.enable()
readMessage.read()
wrapper.addEventListener 'scroll', ->
template.atBottom = false
onscroll()
updateUnreadCount()
wrapper.addEventListener 'mousewheel', ->
template.atBottom = false
onscroll()
readMessage.enable()
readMessage.read()
wrapper.addEventListener 'wheel', ->
template.atBottom = false
onscroll()
readMessage.enable()
readMessage.read()
# salva a data da renderização para exibir alertas de novas mensagens
$.data(this.firstNode, 'renderedAt', new Date)
webrtc.onRemoteUrl = (url) ->
RocketChat.TabBar.openFlex()
Session.set('remoteVideoUrl', url)
webrtc.onSelfUrl = (url) ->
RocketChat.TabBar.openFlex()
Session.set('selfVideoUrl', url)
renameRoom = (rid, name) ->
name = name?.toLowerCase().trim()
console.log 'room renameRoom' if window.rocketDebug
room = Session.get('roomData' + rid)
if room.name is name
Session.set('editRoomTitle', false)
return false
Meteor.call 'saveRoomName', rid, name, (error, result) ->
if result
Session.set('editRoomTitle', false)
# If room was renamed then close current room and send user to the new one
RoomManager.close room.t + room.name
switch room.t
when 'c'
FlowRouter.go 'channel', name: name
when 'p'
FlowRouter.go 'group', name: name
toastr.success t('Room_name_changed_successfully')
if error
if error.error is 'name-invalid'
toastr.error t('Invalid_room_name', name)
return
if error.error is 'duplicate-name'
if room.t is 'c'
toastr.error t('Duplicate_channel_name', name)
else
toastr.error t('Duplicate_private_group_name', name)
return
toastr.error error.reason
toggleAddUser = ->
console.log 'room toggleAddUser' if window.rocketDebug
btn = $('.add-user')
$('.add-user-search').toggleClass('show-search')
if $('i', btn).hasClass('icon-plus')
$('#user-add-search').focus()
$('i', btn).removeClass('icon-plus').addClass('icon-cancel')
else
$('#user-add-search').val('')
$('i', btn).removeClass('icon-cancel').addClass('icon-plus')