diff options
Diffstat (limited to 'webclient')
-rw-r--r-- | webclient/app.js | 1 | ||||
-rw-r--r-- | webclient/components/matrix/event-handler-service.js | 104 | ||||
-rw-r--r-- | webclient/components/matrix/notification-service.js | 104 | ||||
-rw-r--r-- | webclient/index.html | 1 | ||||
-rw-r--r-- | webclient/room/room-controller.js | 38 | ||||
-rw-r--r-- | webclient/room/room.html | 2 |
6 files changed, 153 insertions, 97 deletions
diff --git a/webclient/app.js b/webclient/app.js index 8d9b662ee9..c091f8c6cf 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -30,6 +30,7 @@ var matrixWebClient = angular.module('matrixWebClient', [ 'MatrixCall', 'eventStreamService', 'eventHandlerService', + 'notificationService', 'infinite-scroll', 'ui.bootstrap', 'monospaced.elastic' diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 6f251eec56..e63584510b 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -27,8 +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', '$timeout', 'mPresence', -function(matrixService, $rootScope, $q, $timeout, mPresence) { +.factory('eventHandlerService', ['matrixService', '$rootScope', '$q', '$timeout', 'mPresence', 'notificationService', +function(matrixService, $rootScope, $q, $timeout, mPresence, notificationService) { var ROOM_CREATE_EVENT = "ROOM_CREATE_EVENT"; var MSG_EVENT = "MSG_EVENT"; var MEMBER_EVENT = "MEMBER_EVENT"; @@ -45,71 +45,6 @@ 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 || $.type(content) != "string") { - return false; - } - var bingWords = matrixService.config().bingWords; - var shouldBing = false; - - // case-insensitive name check for user_id OR display_name if they exist - var userRegex = ""; - var myUserId = matrixService.config().user_id; - if (myUserId) { - var localpart = getLocalPartFromUserId(myUserId); - if (localpart) { - localpart = localpart.toLocaleLowerCase(); - userRegex += "\\b" + localpart + "\\b"; - } - } - var myDisplayName = matrixService.config().display_name; - if (myDisplayName) { - myDisplayName = myDisplayName.toLocaleLowerCase(); - if (userRegex.length > 0) { - userRegex += "|"; - } - userRegex += "\\b" + myDisplayName + "\\b"; - } - - var r = new RegExp(userRegex, 'i'); - if (content.search(r) >= 0) { - shouldBing = true; - } - - 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<bingWords.length; i++) { - var re = RegExp(bingWords[i]); - if (content.search(re) != -1) { - shouldBing = true; - break; - } - } - } - return shouldBing; - }; - - var getLocalPartFromUserId = function(user_id) { - if (!user_id) { - return null; - } - var localpartRegex = /@(.*):\w+/i - var results = localpartRegex.exec(user_id); - if (results && results.length == 2) { - return results[1]; - } - return null; - }; var initialSyncDeferred; @@ -228,7 +163,12 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { } if (window.Notification && event.user_id != matrixService.config().user_id) { - var shouldBing = $rootScope.containsBingWord(event.content.body); + 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). // @@ -258,6 +198,9 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { 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]; @@ -269,22 +212,15 @@ function(matrixService, $rootScope, $q, $timeout, mPresence) { roomTitle = event.room_id; } - var notification = new window.Notification( - displayname + - " (" + roomTitle + ")", - { - "body": message, - "icon": member ? member.avatar_url : undefined - }); - - notification.onclick = function() { - console.log("notification.onclick() room=" + event.room_id); - $rootScope.goToPage('room/' + (event.room_id)); - }; - - $timeout(function() { - notification.close(); - }, 5 * 1000); + 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); + } + ); } } } diff --git a/webclient/components/matrix/notification-service.js b/webclient/components/matrix/notification-service.js new file mode 100644 index 0000000000..9a911413c3 --- /dev/null +++ b/webclient/components/matrix/notification-service.js @@ -0,0 +1,104 @@ +/* +Copyright 2014 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +/* +This service manages notifications: enabling, creating and showing them. This +also contains 'bing word' logic. +*/ +angular.module('notificationService', []) +.factory('notificationService', ['$timeout', function($timeout) { + + var getLocalPartFromUserId = function(user_id) { + if (!user_id) { + return null; + } + var localpartRegex = /@(.*):\w+/i + var results = localpartRegex.exec(user_id); + if (results && results.length == 2) { + return results[1]; + } + return null; + }; + + return { + + containsBingWord: function(userId, displayName, bingWords, content) { + // case-insensitive name check for user_id OR display_name if they exist + var userRegex = ""; + if (userId) { + var localpart = getLocalPartFromUserId(userId); + if (localpart) { + localpart = localpart.toLocaleLowerCase(); + userRegex += "\\b" + localpart + "\\b"; + } + } + if (displayName) { + displayName = displayName.toLocaleLowerCase(); + if (userRegex.length > 0) { + userRegex += "|"; + } + userRegex += "\\b" + displayName + "\\b"; + } + + var regexList = [new RegExp(userRegex, 'i')]; + + // bing word list check + if (bingWords && bingWords.length > 0) { + for (var i=0; i<bingWords.length; i++) { + var re = RegExp(bingWords[i], 'i'); + regexList.push(re); + } + } + return this.hasMatch(regexList, content); + }, + + hasMatch: function(regExps, content) { + if (!content || $.type(content) != "string") { + return false; + } + + if (regExps && regExps.length > 0) { + for (var i=0; i<regExps.length; i++) { + if (content.search(regExps[i]) != -1) { + return true; + } + } + } + return false; + }, + + showNotification: function(title, body, icon, onclick) { + var notification = new window.Notification( + title, + { + "body": body, + "icon": icon + } + ); + + if (onclick) { + notification.onclick = onclick; + } + + $timeout(function() { + notification.close(); + }, 5 * 1000); + } + }; + +}]); diff --git a/webclient/index.html b/webclient/index.html index d8b9c95353..bc011a6c72 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -41,6 +41,7 @@ <script src="components/matrix/matrix-phone-service.js"></script> <script src="components/matrix/event-stream-service.js"></script> <script src="components/matrix/event-handler-service.js"></script> + <script src="components/matrix/notification-service.js"></script> <script src="components/matrix/presence-service.js"></script> <script src="components/fileInput/file-input-directive.js"></script> <script src="components/fileUpload/file-upload-service.js"></script> diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 59274baccb..486ead0da9 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -15,11 +15,21 @@ limitations under the License. */ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) -.controller('RoomController', ['$modal', '$filter', '$scope', '$timeout', '$routeParams', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventHandlerService', 'mFileUpload', 'matrixPhoneService', 'MatrixCall', - function($modal, $filter, $scope, $timeout, $routeParams, $location, $rootScope, matrixService, mPresence, eventHandlerService, mFileUpload, matrixPhoneService, MatrixCall) { +.controller('RoomController', ['$modal', '$filter', '$scope', '$timeout', '$routeParams', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventHandlerService', 'mFileUpload', 'matrixPhoneService', 'MatrixCall', 'notificationService', + function($modal, $filter, $scope, $timeout, $routeParams, $location, $rootScope, matrixService, mPresence, eventHandlerService, mFileUpload, matrixPhoneService, MatrixCall, notificationService) { 'use strict'; var MESSAGES_PER_PAGINATION = 30; var THUMBNAIL_SIZE = 320; + + // .html needs this + $scope.containsBingWord = function(content) { + return notificationService.containsBingWord( + matrixService.config().user_id, + matrixService.config().display_name, + matrixService.config().bingWords, + content + ); + }; // Room ids. Computed and resolved in onInit $scope.room_id = undefined; @@ -191,16 +201,20 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) // Notify when a user joins if ((document.hidden || matrixService.presence.unavailable === mPresence.getState()) && event.state_key !== $scope.state.user_id && "join" === event.membership) { - 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); + var userName = event.content.displayname; + if (!userName) { + userName = event.state_key; + } + notificationService.showNotification( + userName + + " (" + (matrixService.getRoomIdToAliasMapping(event.room_id) || event.room_id) + ")", + userName + " joined", + event.content.avatar_url ? event.content.avatar_url : undefined, + function() { + console.log("notification.onclick() room=" + event.room_id); + $rootScope.goToPage('room/' + event.room_id); + } + ); } } } diff --git a/webclient/room/room.html b/webclient/room/room.html index fac7433a4b..5265f42dd8 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -133,7 +133,7 @@ </div> </td> <td class="avatar"> - <img class="avatarImage" ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.png' }}" width="32" height="32" + <img class="avatarImage" ng-src="{{ members[msg.user_id].avatar_url || 'img/default-profile.png' }}" width="32" height="32" title="{{msg.user_id}}" ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id || msg.user_id === state.user_id"/> </td> <td ng-class="(!msg.content.membership && ('m.room.topic' !== msg.type && 'm.room.name' !== msg.type))? (msg.content.msgtype === 'm.emote' ? 'emote text' : 'text') : 'membership text'"> |