Skip to content

Commit

Permalink
Merge pull request #733 from RocketChat/unread
Browse files Browse the repository at this point in the history
Unread
  • Loading branch information
rodrigok committed Sep 8, 2015
2 parents 9a0f1e6 + 8153a6f commit 901d6d6
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 43 deletions.
11 changes: 10 additions & 1 deletion client/lib/RoomHistoryManager.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

room.isLoading.set true

#$('.messages-box .wrapper').data('previous-height', $('.messages-box .wrapper').get(0)?.scrollHeight - $('.messages-box .wrapper').get(0)?.scrollTop)
# ScrollListener.setLoader true
lastMessage = ChatMessage.findOne({rid: rid}, {sort: {ts: 1}})
# lastMessage ?= ChatMessage.findOne({rid: rid}, {sort: {ts: 1}})
Expand All @@ -30,7 +29,17 @@
ts = new Date

Meteor.call 'loadHistory', rid, ts, limit, 0, (err, result) ->
wrapper = $('.messages-box .wrapper').get(0)
previousHeight = wrapper.scrollHeight

ChatMessage.insert item for item in result

heightDiff = wrapper.scrollHeight - previousHeight
wrapper.scrollTop += heightDiff

Meteor.defer ->
readMessage.refreshUnreadMark(rid)

room.isLoading.set false
room.loaded += result.length
if result.length < limit
Expand Down
2 changes: 2 additions & 0 deletions client/lib/RoomManager.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ onDeleteMessageStream = (msg) ->
openedRooms[typeName] =
active: false
ready: false
unreadCount: new ReactiveVar 0
unreadSince: new ReactiveVar undefined

setRoomExpireExcept typeName

Expand Down
84 changes: 62 additions & 22 deletions client/lib/readMessages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,43 @@
- The default method *read* has a delay of 2000ms to prevent multiple reads and to user be able to see the mark
###

Meteor.startup ->
window.addEventListener 'focus', ->
readMessage.refreshUnreadMark()

@readMessage = new class
constructor: ->
@canReadMessage = false

readNow: (force=false) ->
return if @canReadMessage is false
self = @
return if force isnt true and @canReadMessage is false

rid = Session.get 'openedRoom'
if rid?
subscription = ChatSubscription.findOne rid: rid
if subscription? and (subscription.alert is true or subscription.unread > 0)
# Only read messages if user saw the first unread message
position = $('.message.first-unread').position()
if force is true or not position? or position.top >= 0
Meteor.call 'readMessages', rid
if not rid?
return

if force is true
return Meteor.call 'readMessages', rid, ->
self.refreshUnreadMark()

subscription = ChatSubscription.findOne rid: rid
if not subscription? or (subscription.alert is false and subscription.unread is 0)
return

room = RoomManager.openedRooms[subscription.t + subscription.name]
if not room?
return

# Only read messages if user saw the first unread message
position = $('.message.first-unread').position()
if position? and position.top >= 0
Meteor.call 'readMessages', rid, ->
self.refreshUnreadMark()

read: _.debounce (force) ->
@readNow(force)
, 2000
, 1000

disable: ->
@canReadMessage = false
Expand All @@ -37,20 +55,42 @@
return @canReadMessage is true

refreshUnreadMark: (rid) ->
self = @
@disable()
rid ?= Session.get 'openedRoom'
if rid?
subscription = ChatSubscription.findOne rid: rid
if not subscription? then return

room = RoomManager.openedRooms[subscription.t + subscription.name]
if room?
$roomDom = $(room.dom)
$roomDom.find('.message.first-unread').addClass('first-unread-opaque')
if (subscription.rid isnt rid or readMessage.isEnable() is false) and (subscription.alert or subscription.unread > 0)
$roomDom.find('.message.first-unread').removeClass('first-unread').removeClass('first-unread-opaque')
firstUnreadId = ChatMessage.findOne({rid: subscription.rid, ts: {$gt: subscription.ls}, 'u._id': {$ne: Meteor.userId()}}, {sort: {ts: 1}})?._id
if firstUnreadId?
$roomDom.find('.message#'+firstUnreadId).addClass('first-unread')
if not rid?
return @enable()

subscription = ChatSubscription.findOne rid: rid
if not subscription?
return @enable()

room = RoomManager.openedRooms[subscription.t + subscription.name]
if not room?
return @enable()

room.loadingUnread = true

$roomDom = $(room.dom)
$roomDom.find('.message.first-unread').addClass('first-unread-opaque')

# if (subscription.rid isnt rid or readMessage.isEnable() is false)

if not subscription.alert and subscription.unread is 0
room.unreadLoading = false
room.unreadCount.set 0
return @enable()

$roomDom.find('.message.first-unread').removeClass('first-unread').removeClass('first-unread-opaque')
Meteor.call 'countAndFirstId', subscription.rid, (error, data) ->
room.unreadLoading = false
room.unreadCount.set data.count
room.unreadSince.set data.since
room.unreadFirstId = data.firstUnreadId

self.enable()
if data.firstUnreadId?
$roomDom.find('.message#'+data.firstUnreadId).addClass('first-unread')


Meteor.startup ->
Expand Down
1 change: 0 additions & 1 deletion client/routes/roomRoute.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ openRoom = (type, name) ->
readMessage.disable()
Meteor.setTimeout ->
readMessage.refreshUnreadMark()
readMessage.enable()
readMessage.readNow()
, 2000
# KonchatNotification.removeRoomNotification(params._id)
Expand Down
34 changes: 30 additions & 4 deletions client/stylesheets/base.less
Original file line number Diff line number Diff line change
Expand Up @@ -1914,6 +1914,30 @@ a.github-fork {
}
}

.unread-bar {
position: absolute;
top: 60px;
width: 100%;
z-index: 11;
font-weight: bold;
background-color: #E6F4FD;
line-height: 30px;
font-size: 12px;
padding: 0 10px;
box-shadow: 1px 1px 2px rgba(0,0,0,.2);
color: #068FE4;
text-transform: uppercase;
text-align: center;

> a {
float: right;

&:hover {
cursor: pointer;
}
}
}

.upload-progress {
position: absolute;
top: 60px;
Expand Down Expand Up @@ -2205,11 +2229,13 @@ a.github-fork {
padding: 21px 0 10px;
}
.load-more {
text-transform: lowercase;
text-align: center;
span {
border: 1px solid;
border-radius: 20px;
padding: 5px 14px;
line-height: 40px;
font-style: italic;

.load-more-loading {
color: #aaa;
}
}
.start {
Expand Down
34 changes: 23 additions & 11 deletions client/views/app/room.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Template.room.helpers
return RoomHistoryManager.hasMore this._id

isLoading: ->
return 'btn-loading' if RoomHistoryManager.isLoading this._id
return RoomHistoryManager.isLoading this._id

windowId: ->
return "chat-window-#{this._id}"
Expand Down Expand Up @@ -276,6 +276,17 @@ Template.room.helpers
canRecordAudio: ->
return navigator.getUserMedia? or navigator.webkitGetUserMedia?

roomManager: ->
room = ChatRoom.findOne(this._id, { reactive: false })
return RoomManager.openedRooms[room.t + room.name]

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'})

Template.room.events
"keydown #room-search": (e) ->
Expand Down Expand Up @@ -313,6 +324,9 @@ Template.room.events
"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 (Session.get('flexOpened'))
Session.set('rtcLayoutmode', 0)
Expand Down Expand Up @@ -440,9 +454,6 @@ Template.room.events
if result?.rid?
FlowRouter.go('direct', { username: Session.get('showUserInfo') })

'click button.load-more': (e) ->
RoomHistoryManager.getMore @_id

'autocompleteselect #user-add-search': (event, template, doc) ->
roomData = Session.get('roomData' + Session.get('openedRoom'))

Expand Down Expand Up @@ -478,13 +489,14 @@ Template.room.events

$('#room-search').val('')

# 'scroll .wrapper': (e, instance) ->
# console.log 'room scroll .wrapper' if window.rocketDebug
# if e.currentTarget.offsetHeight + e.currentTarget.scrollTop < e.currentTarget.scrollHeight
# instance.scrollOnBottom = false
# else
# instance.scrollOnBottom = true
# $('.new-message').addClass('not')
'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
Expand Down
17 changes: 13 additions & 4 deletions client/views/app/room.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,24 @@ <h2>
</div>
{{/each}}
</div>
{{#if roomManager.unreadCount.get}}
<div class="unread-bar">
{{_ "S_new_messages_since_s" roomManager.unreadCount.get formatUnreadSince}}
<a>
{{_ "Mark_as_read"}}
</a>
</div>
{{/if}}
<div class="messages-box">
<div class="wrapper">
<ul>
{{#if hasMore}}
<li class="load-more">
<button class="button secondary load-more {{isLoading}}">
<i class="icon-spin4 animate-spin loading-icon hidden"></i>
<div>{{_ "Load_more"}}</div>
</button>
{{#if isLoading}}
<div class="load-more-loading">{{_ "Loading_more_from_history"}}...</div>
{{else}}
<a href="">{{_ "Has_more"}}...</a>
{{/if}}
</li>
{{else}}
<li class="start">
Expand Down
4 changes: 4 additions & 0 deletions i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"Get_to_know_the_team" : "Get to know the Rocket.Team",
"github_no_public_email" : "You don't have any email as public email in your GitHub account",
"Have_your_own_chat" : "Have your own web chat. Developed with Meteor.com, the Rocket.Chat is a great solution for developers looking forward to build and evolve their own chat platform.",
"Has_more" : "Has more",
"Hide_room" : "Hide room",
"History" : "History",
"hours" : "hours",
Expand Down Expand Up @@ -137,13 +138,15 @@
"Leave_room" : "Leave room",
"line" : "line",
"Load_more" : "Load more",
"Loading_more_from_history" : "Loading more from history",
"Loading..." : "Loading...",
"Loading_suggestion" : "Loading suggestions...",
"Login" : "Login",
"Login_with" : "Login with %s",
"login_with" : "Or login directly with",
"Logout" : "Logout",
"Make_Admin" : "Make Admin",
"Mark_as_read" : "Mark as read",
"Members" : "Members",
"Members_List" : "Members List",
"Members_placeholder" : "Members",
Expand Down Expand Up @@ -278,6 +281,7 @@
"Stats_Total_Users" : "Total Users",
"strike" : "strike",
"Submit" : "Submit",
"S_new_messages_since_s": "%s new messages since %s",
"The_field_is_required" : "The field %s is required.",
"True" : "True",
"Unnamed" : "Unnamed",
Expand Down
37 changes: 37 additions & 0 deletions server/methods/countAndFirstId.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Meteor.methods
countAndFirstId: (rid) ->
subscription = ChatSubscription.findOne
rid: rid
'u._id': Meteor.userId()

query =
rid: rid
ts:
$gt: subscription.ls
'u._id':
$ne: Meteor.userId()

options =
sort:
ts: 1
limit: 1

firstUnread = ChatMessage.find(query, options).fetch()[0]
if not firstUnread?
return {
firstUnreadId: undefined
count: 0
since: subscription.ls
}

options =
sort:
ts: 1

count = ChatMessage.find(query, options).count()

return {
firstUnreadId: firstUnread._id
count: count
since: subscription.ls
}

0 comments on commit 901d6d6

Please sign in to comment.