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/app/ui-utils/client/lib/readMessages.js

185 lines
4.7 KiB

import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import EventEmitter from 'wolfy87-eventemitter';
import { RoomHistoryManager } from './RoomHistoryManager';
import { RoomManager } from './RoomManager';
import { ChatSubscription, ChatMessage } from '../../../models';
/* DEFINITIONS
- If window loses focus user needs to scroll or click/touch some place
- On hit ESC enable read, force read of current room and remove unread mark
- When user change room disable read until user interaction
- Only read if mark of *first-unread* is visible for user or if flag *force* was passed
- Always read the opened room
- 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(undefined, true)
export const readMessage = new class extends EventEmitter {
constructor() {
super();
this.debug = false;
this.enable();
}
read(rid = Session.get('openedRoom')) {
if (!this.enabled) {
this.log('readMessage -> readNow canceled by enabled: false');
return;
}
const subscription = ChatSubscription.findOne({ rid });
if (subscription == null) {
this.log('readMessage -> readNow canceled, no subscription found for rid:', rid);
return;
}
if ((subscription.alert === false) && (subscription.unread === 0)) {
this.log('readMessage -> readNow canceled, alert', subscription.alert, 'and unread', subscription.unread);
return;
}
const room = RoomManager.getOpenedRoomByRid(rid);
if (room == null) {
this.log('readMessage -> readNow canceled, no room found for typeName:', subscription.t + subscription.name);
return;
}
// Only read messages if user saw the first unread message
const unreadMark = $('.message.first-unread');
if (unreadMark.length > 0) {
const position = unreadMark.position();
const visible = (position != null ? position.top : undefined) >= 0;
if (!visible && room.unreadSince.get()) {
this.log('readMessage -> readNow canceled, unread mark visible:', visible, 'unread since exists', room.unreadSince.get() != null);
return;
}
// if unread mark is not visible and there is more more not loaded unread messages
} else if (RoomHistoryManager.getRoom(rid).unreadNotLoaded.get() > 0) {
return;
}
return this.readNow(rid);
}
readNow(rid = Session.get('openedRoom')) {
if (rid == null) {
this.log('readMessage -> readNow canceled, no rid informed');
return;
}
return Meteor.call('readMessages', rid, () => {
RoomHistoryManager.getRoom(rid).unreadNotLoaded.set(0);
return this.emit(rid);
});
}
log(...args) {
return this.debug && console.log(...args);
}
disable() {
this.enabled = false;
}
enable() {
this.enabled = document.hasFocus();
}
isEnable() {
return this.enabled === true;
}
refreshUnreadMark(rid) {
if (rid == null) {
return;
}
const subscription = ChatSubscription.findOne({ rid }, { reactive: false });
if (subscription == null) {
return;
}
const room = RoomManager.openedRooms[subscription.t + subscription.name];
if (room == null) {
return;
}
if (!subscription.alert && (subscription.unread === 0)) {
const roomDom = $(room.dom);
roomDom.find('.message.first-unread').removeClass('first-unread');
room.unreadSince.set(undefined);
return;
}
let lastReadRecord = ChatMessage.findOne({
rid: subscription.rid,
ts: {
$lt: subscription.ls,
},
}, {
sort: {
ts: -1,
},
});
const { unreadNotLoaded } = RoomHistoryManager.getRoom(rid);
if (lastReadRecord == null && unreadNotLoaded.get() === 0) {
lastReadRecord = { ts: new Date(0) };
}
room.unreadSince.set((lastReadRecord || unreadNotLoaded.get() > 0) && subscription.ls);
if (!lastReadRecord) {
return;
}
const firstUnreadRecord = ChatMessage.findOne({
rid: subscription.rid,
ts: {
$gt: lastReadRecord.ts,
},
'u._id': {
$ne: Meteor.userId(),
},
}, {
sort: {
ts: 1,
},
});
if (firstUnreadRecord) {
room.unreadFirstId = firstUnreadRecord._id;
const roomDom = $(room.dom);
roomDom.find('.message.first-unread').removeClass('first-unread');
roomDom.find(`.message#${ firstUnreadRecord._id }`).addClass('first-unread');
}
}
}();
Meteor.startup(function() {
$(window)
.on('blur', () => readMessage.disable())
.on('focus', () => {
readMessage.enable();
readMessage.read();
})
.on('touchend', () => {
readMessage.enable();
})
.on('keyup', (e) => {
const key = e.which;
if (key === 27) { // ESCAPE KEY
const rid = Session.get('openedRoom');
if (!rid) {
return;
}
readMessage.readNow(rid);
readMessage.refreshUnreadMark(rid);
}
});
});