From 53385784271142108b9adf6b937c3555ccc8cc59 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 09:43:01 -0300 Subject: [PATCH 1/6] Add unread bar --- client/lib/RoomManager.coffee | 2 + client/lib/readMessages.coffee | 86 ++++++++++++++++++++------- client/routes/roomRoute.coffee | 1 - client/stylesheets/base.less | 24 ++++++++ client/views/app/room.coffee | 11 ++++ client/views/app/room.html | 8 +++ server/methods/countAndFirstId.coffee | 37 ++++++++++++ 7 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 server/methods/countAndFirstId.coffee diff --git a/client/lib/RoomManager.coffee b/client/lib/RoomManager.coffee index 61c703c66a18..48ba7db3b265 100644 --- a/client/lib/RoomManager.coffee +++ b/client/lib/RoomManager.coffee @@ -124,6 +124,8 @@ onDeleteMessageStream = (msg) -> openedRooms[typeName] = active: false ready: false + unreadCount: new ReactiveVar 0 + unreadSince: new ReactiveVar undefined setRoomExpireExcept typeName diff --git a/client/lib/readMessages.coffee b/client/lib/readMessages.coffee index e04e719b222b..9e551375d381 100644 --- a/client/lib/readMessages.coffee +++ b/client/lib/readMessages.coffee @@ -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 @@ -37,20 +55,44 @@ 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() + console.log arguments + # firstUnreadId = ChatMessage.findOne({rid: subscription.rid, ts: {$gt: subscription.ls}, 'u._id': {$ne: Meteor.userId()}}, {sort: {ts: 1}})?._id + if data.firstUnreadId? + $roomDom.find('.message#'+data.firstUnreadId).addClass('first-unread') Meteor.startup -> diff --git a/client/routes/roomRoute.coffee b/client/routes/roomRoute.coffee index 6ae3d24a4ccd..e48d4c45245b 100644 --- a/client/routes/roomRoute.coffee +++ b/client/routes/roomRoute.coffee @@ -40,7 +40,6 @@ openRoom = (type, name) -> readMessage.disable() Meteor.setTimeout -> readMessage.refreshUnreadMark() - readMessage.enable() readMessage.readNow() , 2000 # KonchatNotification.removeRoomNotification(params._id) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 40826063783b..1ba7159df34c 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -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; diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 53e5d05e522b..4941365be6ba 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -276,6 +276,14 @@ 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: (date) -> + if not date? then return + + return moment(date).calendar(null, {sameDay: 'LT'}) Template.room.events "keydown #room-search": (e) -> @@ -313,6 +321,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) diff --git a/client/views/app/room.html b/client/views/app/room.html index e7d5a7e3a430..f9f815fc1b90 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -38,6 +38,14 @@

{{/each}} + {{#if roomManager.unreadCount.get}} +
+ {{roomManager.unreadCount.get}} new messages since {{formatUnreadSince roomManager.unreadSince.get}} + + mark as read + +
+ {{/if}}
    diff --git a/server/methods/countAndFirstId.coffee b/server/methods/countAndFirstId.coffee new file mode 100644 index 000000000000..9374839d491c --- /dev/null +++ b/server/methods/countAndFirstId.coffee @@ -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 + } From e33c21ee011b45af22eedc43bcfc7dc853c82e9b Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 09:51:08 -0300 Subject: [PATCH 2/6] Keep scroll on load more messages --- client/lib/RoomHistoryManager.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/lib/RoomHistoryManager.coffee b/client/lib/RoomHistoryManager.coffee index 2b3beb906955..417dba22f531 100644 --- a/client/lib/RoomHistoryManager.coffee +++ b/client/lib/RoomHistoryManager.coffee @@ -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}}) @@ -30,7 +29,14 @@ 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 + room.isLoading.set false room.loaded += result.length if result.length < limit From dbde9ecea35b994c08b277f678906566e5ca832d Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 10:26:50 -0300 Subject: [PATCH 3/6] Load more messages from history automaticly --- client/stylesheets/base.less | 10 ++++++---- client/views/app/room.coffee | 20 +++++++++----------- client/views/app/room.html | 9 +++++---- i18n/en.i18n.json | 2 ++ 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/client/stylesheets/base.less b/client/stylesheets/base.less index 1ba7159df34c..3452d392d982 100644 --- a/client/stylesheets/base.less +++ b/client/stylesheets/base.less @@ -2229,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 { diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index 4941365be6ba..a6672aa2eed2 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -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}" @@ -451,9 +451,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')) @@ -489,13 +486,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 diff --git a/client/views/app/room.html b/client/views/app/room.html index f9f815fc1b90..172fb0ccd778 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -51,10 +51,11 @@

      {{#if hasMore}}
    • - + {{#if isLoading}} +
      {{_ "Loading_more_from_history"}}...
      + {{else}} + {{_ "Has_more"}}... + {{/if}}
    • {{else}}
    • diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3f87bbfffbdb..3a161d4d2ffe 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -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", @@ -137,6 +138,7 @@ "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", From e8e1222e36b8531704b9476e0eb74261f1237c80 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 10:30:46 -0300 Subject: [PATCH 4/6] Refresh unreadMark on load more messages from history --- client/lib/RoomHistoryManager.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/lib/RoomHistoryManager.coffee b/client/lib/RoomHistoryManager.coffee index 417dba22f531..36844beff675 100644 --- a/client/lib/RoomHistoryManager.coffee +++ b/client/lib/RoomHistoryManager.coffee @@ -37,6 +37,9 @@ heightDiff = wrapper.scrollHeight - previousHeight wrapper.scrollTop += heightDiff + Meteor.defer -> + readMessage.refreshUnreadMark(rid) + room.isLoading.set false room.loaded += result.length if result.length < limit From 708657ab254025e8380b22f50f320c24676f7a09 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 10:31:10 -0300 Subject: [PATCH 5/6] Remove logs --- client/lib/readMessages.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/lib/readMessages.coffee b/client/lib/readMessages.coffee index 9e551375d381..f7d4955ffac4 100644 --- a/client/lib/readMessages.coffee +++ b/client/lib/readMessages.coffee @@ -89,8 +89,6 @@ Meteor.startup -> room.unreadFirstId = data.firstUnreadId self.enable() - console.log arguments - # firstUnreadId = ChatMessage.findOne({rid: subscription.rid, ts: {$gt: subscription.ls}, 'u._id': {$ne: Meteor.userId()}}, {sort: {ts: 1}})?._id if data.firstUnreadId? $roomDom.find('.message#'+data.firstUnreadId).addClass('first-unread') From 8153a6fe2e2c4579cde5a320ea8e6b44b43e78b7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Tue, 8 Sep 2015 10:38:40 -0300 Subject: [PATCH 6/6] Move some strings to i18n --- client/views/app/room.coffee | 5 ++++- client/views/app/room.html | 4 ++-- i18n/en.i18n.json | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/client/views/app/room.coffee b/client/views/app/room.coffee index a6672aa2eed2..d68efe37b462 100644 --- a/client/views/app/room.coffee +++ b/client/views/app/room.coffee @@ -280,7 +280,10 @@ Template.room.helpers room = ChatRoom.findOne(this._id, { reactive: false }) return RoomManager.openedRooms[room.t + room.name] - formatUnreadSince: (date) -> + 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'}) diff --git a/client/views/app/room.html b/client/views/app/room.html index 172fb0ccd778..4b0c06c2e973 100644 --- a/client/views/app/room.html +++ b/client/views/app/room.html @@ -40,9 +40,9 @@

{{#if roomManager.unreadCount.get}}
- {{roomManager.unreadCount.get}} new messages since {{formatUnreadSince roomManager.unreadSince.get}} + {{_ "S_new_messages_since_s" roomManager.unreadCount.get formatUnreadSince}} - mark as read + {{_ "Mark_as_read"}}
{{/if}} diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json index 3a161d4d2ffe..a6cdc75a4bd9 100644 --- a/i18n/en.i18n.json +++ b/i18n/en.i18n.json @@ -146,6 +146,7 @@ "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", @@ -280,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",