From 45592ccdfde4c0b9d2452d6ecec8daec903c7df4 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Tue, 16 Sep 2014 15:03:07 +0200 Subject: WEB-29: Improve room page content loading InitialSync: load the 30 last messages of each room so that a full page of messages can be displayed without additionnal request --- webclient/room/room-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 50d902ae47..8cea0511c1 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -235,7 +235,7 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) matrixService.paginateBackMessages($scope.room_id, $rootScope.events.rooms[$scope.room_id].pagination.earliest_token, numItems).then( function(response) { - eventHandlerService.handleRoomMessages($scope.room_id, response.data, false); + eventHandlerService.handleRoomMessages($scope.room_id, response.data, false, 'b'); if (response.data.chunk.length < MESSAGES_PER_PAGINATION) { // no more messages to paginate. this currently never gets turned true again, as we never // expire paginated contents in the current implementation. -- cgit 1.5.1 From a284de73e621e7f67212982046130416c042b386 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Tue, 16 Sep 2014 15:42:31 +0200 Subject: If an initialSync has been already done on a room, we do not need to paginate back to get more messages --- webclient/room/room-controller.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 8cea0511c1..d3888cae86 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -684,6 +684,10 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) // The room members is available in the data fetched by initialSync if ($rootScope.events.rooms[$scope.room_id]) { + + // There is no need to do a 1st pagination (initialSync provided enough to fill a page) + $scope.state.first_pagination = false; + var members = $rootScope.events.rooms[$scope.room_id].members; // Update the member list @@ -743,9 +747,18 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) // Arm list timing update timer updateMemberListPresenceAge(); - // Start pagination + // Allow pagination $scope.state.can_paginate = true; - paginate(MESSAGES_PER_PAGINATION); + + // Do a first pagination only if it is required + // FIXME: Should be no more require when initialSync/{room_id} will be available + if ($scope.state.first_pagination) { + paginate(MESSAGES_PER_PAGINATION); + } + else { + // There are already messages, go to the last message + scrollToBottom(true); + } }, function(error) { $scope.feedback = "Failed get member list: " + error.data.error; -- cgit 1.5.1 From 890178cf25491716289e5c54c045478b1be55d29 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Tue, 16 Sep 2014 16:13:24 +0200 Subject: Fixed scroll flickering when opening the room --- webclient/room/room-controller.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index d3888cae86..2c9a3836e7 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -676,6 +676,10 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) var onInit2 = function() { console.log("onInit2"); + // Scroll down as soon as possible so that we point to the last message + // if it already exists in memory + scrollToBottom(true); + // Make sure the initialSync has been before going further eventHandlerService.waitForInitialSyncCompletion().then( function() { -- cgit 1.5.1 From b170fe921e327d8d1be9768d30305ba953ccae9f Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 14:20:26 +0100 Subject: Added a section on bing words if you enable desktop notifications. --- webclient/room/room-controller.js | 2 +- webclient/settings/settings-controller.js | 11 ++++++++++- webclient/settings/settings.html | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 2c9a3836e7..4a91d298bc 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -139,7 +139,7 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) if (isLive && event.room_id === $scope.room_id) { scrollToBottom(); - + if (window.Notification) { // Show notification when the window is hidden, or the user is idle if (document.hidden || matrixService.presence.unavailable === mPresence.getState()) { diff --git a/webclient/settings/settings-controller.js b/webclient/settings/settings-controller.js index 8c877a24e9..9cdace704a 100644 --- a/webclient/settings/settings-controller.js +++ b/webclient/settings/settings-controller.js @@ -194,7 +194,16 @@ angular.module('SettingsController', ['matrixService', 'mFileUpload', 'mFileInpu /*** Desktop notifications section ***/ $scope.settings = { - notifications: undefined + notifications: undefined, + bingWords: matrixService.config().bingWords + }; + + $scope.saveBingWords = function() { + console.log("Saving words: "+JSON.stringify($scope.settings.bingWords)); + var config = matrixService.config(); + config.bingWords = $scope.settings.bingWords; + matrixService.setConfig(config); + matrixService.saveConfig(); }; // If the browser supports it, check the desktop notification state diff --git a/webclient/settings/settings.html b/webclient/settings/settings.html index c358a6e9d8..3b3dd3dadd 100644 --- a/webclient/settings/settings.html +++ b/webclient/settings/settings.html @@ -52,6 +52,14 @@
Notifications are enabled. +
+

Words to alert on:

+ +
    +
  • {{word}}
  • +
+
You have denied permission for notifications.
-- cgit 1.5.1 From 660364d6a7a4ad69bbb951990c20fc38d168e588 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 14:32:50 +0100 Subject: Move the notification logic out of an individual room controller and into the general event handler, so we can notify for >1 room. --- webclient/components/matrix/event-handler-service.js | 20 +++++++++++++++++++- webclient/room/room-controller.js | 16 ---------------- 2 files changed, 19 insertions(+), 17 deletions(-) (limited to 'webclient/room') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index fc5a81617c..8783b9b1e0 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -27,7 +27,8 @@ Typically, this service will store events or broadcast them to any listeners if typically all the $on method would do is update its own $scope. */ angular.module('eventHandlerService', []) -.factory('eventHandlerService', ['matrixService', '$rootScope', '$q', function(matrixService, $rootScope, $q) { +.factory('eventHandlerService', ['matrixService', '$rootScope', '$q', '$timeout', 'mPresence', +function(matrixService, $rootScope, $q, $timeout, mPresence) { var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT"; var MSG_EVENT = "MSG_EVENT"; var MEMBER_EVENT = "MEMBER_EVENT"; @@ -137,6 +138,23 @@ angular.module('eventHandlerService', []) else { $rootScope.events.rooms[event.room_id].messages.push(event); } + + if (window.Notification) { + // Show notification when the window is hidden, or the user is idle + if (document.hidden || matrixService.presence.unavailable === mPresence.getState()) { + console.log("Displaying notification for "+JSON.stringify(event)); + var notification = new window.Notification( + ($rootScope.events.rooms[event.room_id].members[event.user_id].displayname || event.user_id) + + " (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", // FIXME: don't leak room_ids here + { + "body": event.content.body, + "icon": $rootScope.events.rooms[event.room_id].members[event.user_id].avatar_url + }); + $timeout(function() { + notification.close(); + }, 5 * 1000); + } + } } else { $rootScope.events.rooms[event.room_id].messages.unshift(event); diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 4a91d298bc..4a1dfd6aac 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -139,22 +139,6 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) if (isLive && event.room_id === $scope.room_id) { scrollToBottom(); - - if (window.Notification) { - // Show notification when the window is hidden, or the user is idle - if (document.hidden || matrixService.presence.unavailable === mPresence.getState()) { - var notification = new window.Notification( - ($scope.members[event.user_id].displayname || event.user_id) + - " (" + ($scope.room_alias || $scope.room_id) + ")", // FIXME: don't leak room_ids here - { - "body": event.content.body, - "icon": $scope.members[event.user_id].avatar_url - }); - $timeout(function() { - notification.close(); - }, 5 * 1000); - } - } } }); -- cgit 1.5.1 From a402e0c5e6e432a175b48279c972bc9ae7e944bc Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 15:15:19 +0100 Subject: Added bing detection logic. Persist the display name of the user in localstorage for use when binging. --- .../components/matrix/event-handler-service.js | 37 ++++++++++++++++++++-- webclient/home/home-controller.js | 4 +++ webclient/room/room-controller.js | 4 +-- webclient/settings/settings.html | 6 ++-- 4 files changed, 44 insertions(+), 7 deletions(-) (limited to 'webclient/room') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 8783b9b1e0..16d5763ed2 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -140,8 +140,41 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { } if (window.Notification) { - // Show notification when the window is hidden, or the user is idle - if (document.hidden || matrixService.presence.unavailable === mPresence.getState()) { + var bingWords = matrixService.config().bingWords; + var content = event.content.body; + var shouldBing = false; + + // case-insensitive name check for user_id OR display_name if they exist + var myUserId = matrixService.config().user_id; + if (myUserId) { + myUserId = myUserId.toLocaleLowerCase(); + } + var myDisplayName = matrixService.config().display_name; + if (myDisplayName) { + myDisplayName = myDisplayName.toLocaleLowerCase(); + } + if ( (myDisplayName && content.toLocaleLowerCase().indexOf(myDisplayName) != -1) || + (myUserId && content.toLocaleLowerCase().indexOf(myUserId) != -1) ) { + shouldBing = true; + } + + // bing word list check + if (bingWords && !shouldBing) { + for (var i=0; iDesktop notifications
- Notifications are enabled. + Notifications are enabled. You will be alerted when a message contains your user ID or display name.
-

Words to alert on:

- Additional words to alert on: +
  • {{word}}
  • -- cgit 1.5.1 From b36a0c71d1da1fd23a154389c692f6644a3e7ac2 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 15:31:18 +0100 Subject: Added utility function containsBingWord and hook up some css to it. --- webclient/app.css | 4 ++ .../components/matrix/event-handler-service.js | 71 +++++++++++++--------- webclient/room/room.html | 2 +- 3 files changed, 46 insertions(+), 31 deletions(-) (limited to 'webclient/room') diff --git a/webclient/app.css b/webclient/app.css index 4a4ba7b8f4..b947d8b663 100755 --- a/webclient/app.css +++ b/webclient/app.css @@ -538,6 +538,10 @@ a:active { color: #000; } color: #F00; } +.messageBing { + color: #00F; +} + #room-fullscreen-image { position: absolute; top: 0px; diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 16d5763ed2..389eee5471 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -45,6 +45,46 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { var eventMap = {}; $rootScope.presence = {}; + + // TODO: This is attached to the rootScope so .html can just go containsBingWord + // for determining classes so it is easy to highlight bing messages. It seems a + // bit strange to put the impl in this service though, but I can't think of a better + // file to put it in. + $rootScope.containsBingWord = function(content) { + if (!content) { + return false; + } + var bingWords = matrixService.config().bingWords; + var shouldBing = false; + + // case-insensitive name check for user_id OR display_name if they exist + var myUserId = matrixService.config().user_id; + if (myUserId) { + myUserId = myUserId.toLocaleLowerCase(); + } + var myDisplayName = matrixService.config().display_name; + if (myDisplayName) { + myDisplayName = myDisplayName.toLocaleLowerCase(); + } + if ( (myDisplayName && content.toLocaleLowerCase().indexOf(myDisplayName) != -1) || + (myUserId && content.toLocaleLowerCase().indexOf(myUserId) != -1) ) { + shouldBing = true; + } + + // bing word list check + if (bingWords && !shouldBing) { + for (var i=0; i Outgoing Call -- cgit 1.5.1 From 95e171e19a323bd92da5f20d651a52517b47ce03 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 16 Sep 2014 16:23:20 +0100 Subject: Don't bing for sent messages. Handle cases where the member is unknown rather than erroring out. --- webclient/components/matrix/event-handler-service.js | 11 ++++++++--- webclient/room/room.html | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'webclient/room') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 0c7c0d1696..55e8480a19 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -177,7 +177,7 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { $rootScope.events.rooms[event.room_id].messages.push(event); } - if (window.Notification) { + if (window.Notification && event.user_id != matrixService.config().user_id) { var shouldBing = $rootScope.containsBingWord(event.content.body); // TODO: Binging every message when idle doesn't make much sense. Can we use this more sensibly? @@ -195,12 +195,17 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { if (shouldBing) { console.log("Displaying notification for "+JSON.stringify(event)); + var member = $rootScope.events.rooms[event.room_id].members[event.user_id]; + var displayname = undefined; + if (member) { + displayname = member.displayname; + } var notification = new window.Notification( - ($rootScope.events.rooms[event.room_id].members[event.user_id].displayname || event.user_id) + + (displayname || event.user_id) + " (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", // FIXME: don't leak room_ids here { "body": event.content.body, - "icon": $rootScope.events.rooms[event.room_id].members[event.user_id].avatar_url + "icon": member ? member.avatar_url : undefined }); $timeout(function() { notification.close(); diff --git a/webclient/room/room.html b/webclient/room/room.html index 86ec2e51ca..886c2afe64 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -105,7 +105,7 @@ Outgoing Call -- cgit 1.5.1 From f9bb000ccf9cb6bfa5be3af68ec319f346b313f1 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Wed, 17 Sep 2014 09:41:21 +0200 Subject: WEB-35: joins/parts should trigger desktop notifications --- webclient/room/room-controller.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index f82f4aed27..6e1d83a23d 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -143,7 +143,7 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) }); $scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) { - if (isLive) { + if (isLive && event.room_id === $scope.room_id) { if ($scope.state.waiting_for_joined_event) { // The user has successfully joined the room, we can getting data for this room $scope.state.waiting_for_joined_event = false; @@ -161,19 +161,33 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) else { user = event.user_id; } - if ("ban" === event.membership) { $scope.state.permission_denied = "You have been banned by " + user; } else { $scope.state.permission_denied = "You have been kicked by " + user; - } - + } } else { scrollToBottom(); updateMemberList(event); + + // Notify when a user joins + if ((document.hidden || matrixService.presence.unavailable === mPresence.getState()) + && event.state_key !== $scope.state.user_id && "join" === event.membership) { + debugger; + var notification = new window.Notification( + event.content.displayname + + " (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", // FIXME: don't leak room_ids here + { + "body": event.content.displayname + " joined", + "icon": event.content.avatar_url ? event.content.avatar_url : undefined + }); + $timeout(function() { + notification.close(); + }, 5 * 1000); + } } } }); -- cgit 1.5.1 From d9a9a470758edd596676239271fefb820785e1b3 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Wed, 17 Sep 2014 14:18:39 +0200 Subject: SYWEB-7: Up & down keys let user step through the history as per readline or xchat --- webclient/room/room-controller.js | 72 +++++++++++++++++++++++++++++++++++++-- webclient/room/room.html | 3 +- 2 files changed, 72 insertions(+), 3 deletions(-) (limited to 'webclient/room') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 6e1d83a23d..15056b947a 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -404,12 +404,15 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) }; $scope.send = function() { - if ($scope.textInput === "") { + if (undefined === $scope.textInput || $scope.textInput === "") { return; } scrollToBottom(true); - + + // Store the command in the history + history.push($scope.textInput); + var promise; var cmd; var args; @@ -847,4 +850,69 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) $rootScope.currentCall = call; }; + // Manage history of typed messages + var history = { + // The list of typed messages. Index 0 is the more recents + data: [], + + // The position in the history currently displayed + position: -1, + + // The message the user has started to type before going into the history + typingMessage: undefined, + + // Store a message in the history + push: function(message) { + this.data.unshift(message); + + // Reset history position + this.position = -1; + this.typingMessage = undefined; + }, + + // Move in the history + go: function(offset) { + + if (-1 === this.position) { + // User starts to go to into the history, save the current line + this.typingMessage = $scope.textInput; + } + else { + // If the user modified this line in history, keep the change + this.data[this.position] = $scope.textInput; + } + + // Bounds the new position to valid data + var newPosition = this.position + offset; + newPosition = Math.max(-1, newPosition); + newPosition = Math.min(newPosition, this.data.length - 1); + this.position = newPosition; + + if (-1 !== this.position) { + // Show the message from the history + $scope.textInput = this.data[this.position]; + } + else if (undefined !== this.typingMessage) { + // Go back to the message the user started to type + $scope.textInput = this.typingMessage; + } + } + }; + + // Make history singleton methods available from HTML + $scope.history = { + goUp: function($event) { + if ($scope.room_id) { + history.go(1); + } + $event.preventDefault(); + }, + goDown: function($event) { + if ($scope.room_id) { + history.go(-1); + } + $event.preventDefault(); + } + }; + }]); diff --git a/webclient/room/room.html b/webclient/room/room.html index 886c2afe64..33ad06ea80 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -156,7 +156,8 @@