diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js
index a8d89834ae..589554ec08 100644
--- a/webclient/components/matrix/event-handler-service.js
+++ b/webclient/components/matrix/event-handler-service.js
@@ -96,7 +96,7 @@ function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService
__room.old_room_state.storeStateEvents(room.state);
__room.old_room_state.pagination_token = room.messages.start;
- __room.addMessages(room.messages.chunk);
+ __room.addMessageEvents(room.messages.chunk);
}
};
@@ -108,6 +108,26 @@ function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService
// Generic method to handle events data
var handleRoomDateEvent = function(event, isLiveEvent, addToRoomMessages) {
+ var __room = modelService.getRoom(event.room_id);
+ if (addToRoomMessages) {
+ __room.addMessageEvent(event, !isLiveEvent);
+ }
+ if (isLiveEvent) {
+ __room.current_room_state.storeStateEvent(event);
+ }
+ else {
+ var eventTs = event.origin_server_ts;
+ var storedEvent = __room.current_room_state.getStateEvent(event.type, event.state_key);
+ if (storedEvent) {
+ if (storedEvent.origin_server_ts < eventTs) {
+ // the incoming event is newer, use it.
+ __room.current_room_state.storeStateEvent(event);
+ }
+ }
+ }
+
+ // =====================================
+
// Add topic changes as if they were a room message
if (addToRoomMessages) {
if (isLiveEvent) {
@@ -144,6 +164,70 @@ function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService
var handleRoomAliases = function(event, isLiveEvent) {
matrixService.createRoomIdToAliasMapping(event.room_id, event.content.aliases[0]);
};
+
+ var displayNotification = function(event) {
+ if (window.Notification && event.user_id != matrixService.config().user_id) {
+ var shouldBing = notificationService.containsBingWord(
+ matrixService.config().user_id,
+ matrixService.config().display_name,
+ matrixService.config().bingWords,
+ event.content.body
+ );
+
+ // Ideally we would notify only when the window is hidden (i.e. document.hidden = true).
+ //
+ // However, Chrome on Linux and OSX currently returns document.hidden = false unless the window is
+ // explicitly showing a different tab. So we need another metric to determine hiddenness - we
+ // simply use idle time. If the user has been idle enough that their presence goes to idle, then
+ // we also display notifs when things happen.
+ //
+ // This is far far better than notifying whenever anything happens anyway, otherwise you get spammed
+ // to death with notifications when the window is in the foreground, which is horrible UX (especially
+ // if you have not defined any bingers and so get notified for everything).
+ var isIdle = (document.hidden || matrixService.presence.unavailable === mPresence.getState());
+
+ // We need a way to let people get notifications for everything, if they so desire. The way to do this
+ // is to specify zero bingwords.
+ var bingWords = matrixService.config().bingWords;
+ if (bingWords === undefined || bingWords.length === 0) {
+ shouldBing = true;
+ }
+
+ if (shouldBing && isIdle) {
+ console.log("Displaying notification for "+JSON.stringify(event));
+ var member = getMember(event.room_id, event.user_id);
+ var displayname = getUserDisplayName(event.room_id, event.user_id);
+
+ var message = event.content.body;
+ if (event.content.msgtype === "m.emote") {
+ message = "* " + displayname + " " + message;
+ }
+ else if (event.content.msgtype === "m.image") {
+ message = displayname + " sent an image.";
+ }
+
+ var roomTitle = matrixService.getRoomIdToAliasMapping(event.room_id);
+ var theRoom = $rootScope.events.rooms[event.room_id];
+ if (!roomTitle && theRoom && theRoom["m.room.name"] && theRoom["m.room.name"].content) {
+ roomTitle = theRoom["m.room.name"].content.name;
+ }
+
+ if (!roomTitle) {
+ roomTitle = event.room_id;
+ }
+
+ notificationService.showNotification(
+ displayname + " (" + roomTitle + ")",
+ message,
+ member ? member.avatar_url : undefined,
+ function() {
+ console.log("notification.onclick() room=" + event.room_id);
+ $rootScope.goToPage('room/' + event.room_id);
+ }
+ );
+ }
+ }
+ };
var handleMessage = function(event, isLiveEvent) {
// Check for empty event content
@@ -156,6 +240,21 @@ function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService
// empty json object is a redacted event, so ignore.
return;
}
+
+ // =======================
+
+ var __room = modelService.getRoom(event.room_id);
+
+ if (event.user_id !== matrixService.config().user_id) {
+ __room.addMessageEvent(event, !isLiveEvent);
+ }
+ else {
+ // we may have locally echoed this, so we should replace the event
+ // instead of just adding.
+ __room.addOrReplaceMessageEvent(event, !isLiveEvent);
+ }
+
+ // =======================
if (isLiveEvent) {
if (event.user_id === matrixService.config().user_id &&
@@ -172,69 +271,10 @@ function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService
}
else {
$rootScope.events.rooms[event.room_id].messages.push(event);
+ displayNotification(event);
}
- if (window.Notification && event.user_id != matrixService.config().user_id) {
- var shouldBing = notificationService.containsBingWord(
- matrixService.config().user_id,
- matrixService.config().display_name,
- matrixService.config().bingWords,
- event.content.body
- );
-
- // Ideally we would notify only when the window is hidden (i.e. document.hidden = true).
- //
- // However, Chrome on Linux and OSX currently returns document.hidden = false unless the window is
- // explicitly showing a different tab. So we need another metric to determine hiddenness - we
- // simply use idle time. If the user has been idle enough that their presence goes to idle, then
- // we also display notifs when things happen.
- //
- // This is far far better than notifying whenever anything happens anyway, otherwise you get spammed
- // to death with notifications when the window is in the foreground, which is horrible UX (especially
- // if you have not defined any bingers and so get notified for everything).
- var isIdle = (document.hidden || matrixService.presence.unavailable === mPresence.getState());
-
- // We need a way to let people get notifications for everything, if they so desire. The way to do this
- // is to specify zero bingwords.
- var bingWords = matrixService.config().bingWords;
- if (bingWords === undefined || bingWords.length === 0) {
- shouldBing = true;
- }
-
- if (shouldBing && isIdle) {
- console.log("Displaying notification for "+JSON.stringify(event));
- var member = getMember(event.room_id, event.user_id);
- var displayname = getUserDisplayName(event.room_id, event.user_id);
-
- var message = event.content.body;
- if (event.content.msgtype === "m.emote") {
- message = "* " + displayname + " " + message;
- }
- else if (event.content.msgtype === "m.image") {
- message = displayname + " sent an image.";
- }
-
- var roomTitle = matrixService.getRoomIdToAliasMapping(event.room_id);
- var theRoom = $rootScope.events.rooms[event.room_id];
- if (!roomTitle && theRoom && theRoom["m.room.name"] && theRoom["m.room.name"].content) {
- roomTitle = theRoom["m.room.name"].content.name;
- }
-
- if (!roomTitle) {
- roomTitle = event.room_id;
- }
-
- notificationService.showNotification(
- displayname + " (" + roomTitle + ")",
- message,
- member ? member.avatar_url : undefined,
- function() {
- console.log("notification.onclick() room=" + event.room_id);
- $rootScope.goToPage('room/' + event.room_id);
- }
- );
- }
- }
+
}
else {
$rootScope.events.rooms[event.room_id].messages.unshift(event);
diff --git a/webclient/components/matrix/model-service.js b/webclient/components/matrix/model-service.js
index 0ba23cb76a..6e1576cd62 100644
--- a/webclient/components/matrix/model-service.js
+++ b/webclient/components/matrix/model-service.js
@@ -36,15 +36,33 @@ angular.module('modelService', [])
this.messages = []; // events which can be displayed on the UI. TODO move?
};
Room.prototype = {
- addMessages: function addMessages(events, toFront) {
+ addMessageEvents: function addMessageEvents(events, toFront) {
for (var i=0; i<events.length; i++) {
- if (toFront) {
- this.messages.unshift(events[i]);
- }
- else {
- this.messages.push(events[i]);
+ this.addMessageEvent(events[i], toFront);
+ }
+ },
+
+ addMessageEvent: function addMessageEvent(event, toFront) {
+ if (toFront) {
+ this.messages.unshift(event);
+ }
+ else {
+ this.messages.push(event);
+ }
+ },
+
+ addOrReplaceMessageEvent: function addOrReplaceMessageEvent(event, toFront) {
+ // Start looking from the tail since the first goal of this function
+ // is to find a message among the latest ones
+ for (var i = this.messages.length - 1; i >= 0; i--) {
+ var storedEvent = this.messages[i];
+ if (storedEvent.event_id === event.event_id) {
+ // It's clobbering time!
+ this.messages[i] = event;
+ return;
}
}
+ this.addMessageEvent(event, toFront);
},
leave: function leave() {
@@ -81,6 +99,10 @@ angular.module('modelService', [])
for (var i=0; i<events.length; i++) {
this.storeStateEvent(events[i]);
}
+ },
+
+ getStateEvent: function getStateEvent(event_type, state_key) {
+ return this.state_events[event_type + state_key];
}
};
|