summary refs log tree commit diff
path: root/webclient/room
diff options
context:
space:
mode:
Diffstat (limited to 'webclient/room')
-rw-r--r--webclient/room/room-controller.js125
-rw-r--r--webclient/room/room.html82
2 files changed, 178 insertions, 29 deletions
diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js

index 78520a829d..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; @@ -133,7 +143,9 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) // Do not autoscroll to the bottom to display the new event if the user is not at the bottom. // Exception: in case where the event is from the user, we want to force scroll to the bottom var objDiv = document.getElementById("messageTableWrapper"); - if ((objDiv.offsetHeight + objDiv.scrollTop >= objDiv.scrollHeight) || force) { + // add a 10px buffer to this check so if the message list is not *quite* + // at the bottom it still scrolls since it basically is at the bottom. + if ((10 + objDiv.offsetHeight + objDiv.scrollTop >= objDiv.scrollHeight) || force) { $timeout(function() { objDiv.scrollTop = objDiv.scrollHeight; @@ -189,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); + } + ); } } } @@ -983,10 +999,87 @@ angular.module('RoomController', ['ngSanitize', 'matrixFilter', 'mFileInput']) }; $scope.openJson = function(content) { - console.log("Displaying modal dialog for " + JSON.stringify(content)); + $scope.event_selected = content; + // scope this so the template can check power levels and enable/disable + // buttons + $scope.pow = matrixService.getUserPowerLevel; + + var modalInstance = $modal.open({ + templateUrl: 'eventInfoTemplate.html', + controller: 'EventInfoController', + scope: $scope + }); + + modalInstance.result.then(function(action) { + if (action === "redact") { + var eventId = $scope.event_selected.event_id; + console.log("Redacting event ID " + eventId); + matrixService.redactEvent( + $scope.event_selected.room_id, + eventId + ).then(function(response) { + console.log("Redaction = " + JSON.stringify(response)); + }, function(error) { + console.error("Failed to redact event: "+JSON.stringify(error)); + if (error.data.error) { + $scope.feedback = error.data.error; + } + }); + } + }, function() { + // any dismiss code + }); + }; + + $scope.openRoomInfo = function() { + $scope.roomInfo = {}; + $scope.roomInfo.newEvent = { + content: {}, + type: "", + state_key: "" + }; + + var stateFilter = $filter("stateEventsFilter"); + var stateEvents = stateFilter($scope.events.rooms[$scope.room_id]); + // The modal dialog will 2-way bind this field, so we MUST make a deep + // copy of the state events else we will be *actually adjusing our view + // of the world* when fiddling with the JSON!! Apparently parse/stringify + // is faster than jQuery's extend when doing deep copies. + $scope.roomInfo.stateEvents = JSON.parse(JSON.stringify(stateEvents)); var modalInstance = $modal.open({ - template: "<pre>" + angular.toJson(content, true) + "</pre>" + templateUrl: 'roomInfoTemplate.html', + controller: 'RoomInfoController', + size: 'lg', + scope: $scope }); }; -}]); +}]) +.controller('EventInfoController', function($scope, $modalInstance) { + console.log("Displaying modal dialog for >>>> " + JSON.stringify($scope.event_selected)); + $scope.redact = function() { + console.log("User level = "+$scope.pow($scope.room_id, $scope.state.user_id)+ + " Redact level = "+$scope.events.rooms[$scope.room_id]["m.room.ops_levels"].content.redact_level); + console.log("Redact event >> " + JSON.stringify($scope.event_selected)); + $modalInstance.close("redact"); + }; +}) +.controller('RoomInfoController', function($scope, $modalInstance, $filter, matrixService) { + console.log("Displaying room info."); + + $scope.submit = function(event) { + if (event.content) { + console.log("submit >>> " + JSON.stringify(event.content)); + matrixService.sendStateEvent($scope.room_id, event.type, + event.content, event.state_key).then(function(response) { + $modalInstance.dismiss(); + }, function(err) { + $scope.feedback = err.data.error; + } + ); + } + }; + + $scope.dismiss = $modalInstance.dismiss; + +}); diff --git a/webclient/room/room.html b/webclient/room/room.html
index e753b037fe..5265f42dd8 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html
@@ -1,5 +1,59 @@ <div ng-controller="RoomController" data-ng-init="onInit()" class="room" style="height: 100%;"> + <script type="text/ng-template" id="eventInfoTemplate.html"> + <div class="modal-body"> + <pre> {{event_selected | json}} </pre> + </div> + <div class="modal-footer"> + <button ng-click="redact()" type="button" class="btn btn-danger" + ng-disabled="!events.rooms[room_id]['m.room.ops_levels'].content.redact_level || !pow(room_id, state.user_id) || pow(room_id, state.user_id) < events.rooms[room_id]['m.room.ops_levels'].content.redact_level" + title="Delete this event on all home servers. This cannot be undone."> + Redact + </button> + </div> + </script> + + <script type="text/ng-template" id="roomInfoTemplate.html"> + <div class="modal-body"> + <table class="room-info"> + <tr ng-repeat="(key, event) in roomInfo.stateEvents" class="room-info-event"> + <td class="room-info-event-meta" width="30%"> + <span class="monospace">{{ key }}</span> + <br/> + {{ (event.origin_server_ts) | date:'MMM d HH:mm' }} + <br/> + Set by: <span class="monospace">{{ event.user_id }}</span> + <br/> + <span ng-show="event.required_power_level >= 0">Required power level: {{event.required_power_level}}<br/></span> + <button ng-click="submit(event)" type="button" class="btn btn-success" ng-disabled="!event.content"> + Submit + </button> + </td> + <td class="room-info-event-content" width="70%"> + <textarea class="room-info-textarea-content" msd-elastic ng-model="event.content" asjson></textarea> + </td> + </tr> + <tr> + <td class="room-info-event-meta" width="30%"> + <input ng-model="roomInfo.newEvent.type" placeholder="your.event.type" /> + <br/> + <button ng-click="submit(roomInfo.newEvent)" type="button" class="btn btn-success" ng-disabled="!roomInfo.newEvent.content || !roomInfo.newEvent.type"> + Submit + </button> + </td> + <td class="room-info-event-content" width="70%"> + <textarea class="room-info-textarea-content" msd-elastic ng-model="roomInfo.newEvent.content" asjson></textarea> + </td> + </tr> + </table> + </div> + <div class="modal-footer"> + <button ng-click="dismiss()" type="button" class="btn"> + Close + </button> + </div> + </script> + <div id="roomHeader"> <a href ng-click="goToPage('/')"><img src="img/logo-small.png" width="100" height="43" alt="[matrix]"/></a> <div class="roomHeaderInfo"> @@ -79,15 +133,15 @@ </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'"> - <div class="bubble"> - <span ng-if="'join' === msg.content.membership && msg.changedKey === 'membership'" ng-click="openJson(msg)"> + <div class="bubble" ng-click="openJson(msg)"> + <span ng-if="'join' === msg.content.membership && msg.changedKey === 'membership'"> {{ members[msg.state_key].displayname || msg.state_key }} joined </span> - <span ng-if="'leave' === msg.content.membership && msg.changedKey === 'membership'" ng-click="openJson(msg)"> + <span ng-if="'leave' === msg.content.membership && msg.changedKey === 'membership'"> <span ng-if="msg.user_id === msg.state_key"> {{ members[msg.state_key].displayname || msg.state_key }} left </span> @@ -101,7 +155,7 @@ </span> </span> <span ng-if="'invite' === msg.content.membership && msg.changedKey === 'membership' || - 'ban' === msg.content.membership && msg.changedKey === 'membership'" ng-click="openJson(msg)"> + 'ban' === msg.content.membership && msg.changedKey === 'membership'"> {{ members[msg.user_id].displayname || msg.user_id }} {{ {"invite": "invited", "ban": "banned"}[msg.content.membership] }} {{ members[msg.state_key].displayname || msg.state_key }} @@ -109,25 +163,24 @@ : {{ msg.content.reason }} </span> </span> - <span ng-if="msg.changedKey === 'displayname'" ng-click="openJson(msg)"> + <span ng-if="msg.changedKey === 'displayname'"> {{ msg.user_id }} changed their display name from {{ msg.prev_content.displayname }} to {{ msg.content.displayname }} </span> <span ng-show='msg.content.msgtype === "m.emote"' ng-class="msg.echo_msg_state" ng-bind-html="'* ' + (members[msg.user_id].displayname || msg.user_id) + ' ' + msg.content.body | linky:'_blank'" - ng-click="openJson(msg)"/> + /> <span ng-show='msg.content.msgtype === "m.text"' class="message" - ng-click="openJson(msg)" ng-class="containsBingWord(msg.content.body) && msg.user_id != state.user_id ? msg.echo_msg_state + ' messageBing' : msg.echo_msg_state" ng-bind-html="(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message' && msg.content.format === 'org.matrix.custom.html') ? (msg.content.formatted_body | unsanitizedLinky) : (msg.content.msgtype === 'm.text' && msg.type === 'm.room.message') ? (msg.content.body | linky:'_blank') : '' "/> - <span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id' ng-click="openJson(msg)">Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> - <span ng-show='msg.type === "m.call.invite" && msg.user_id != state.user_id' ng-click="openJson(msg)">Incoming Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> + <span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id'>Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> + <span ng-show='msg.type === "m.call.invite" && msg.user_id != state.user_id'>Incoming Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> <div ng-show='msg.content.msgtype === "m.image"'> <div ng-hide='msg.content.thumbnail_url' ng-style="msg.content.body.h && { 'height' : (msg.content.body.h < 320) ? msg.content.body.h : 320}"> @@ -135,15 +188,15 @@ </div> <div ng-show='msg.content.thumbnail_url' ng-style="{ 'height' : msg.content.thumbnail_info.h }"> <img class="image mouse-pointer" ng-src="{{ msg.content.thumbnail_url }}" - ng-click="$parent.fullScreenImageURL = msg.content.url"/> + ng-click="$parent.fullScreenImageURL = msg.content.url; $event.stopPropagation();"/> </div> </div> - <span ng-if="'m.room.topic' === msg.type" ng-click="openJson(msg)"> + <span ng-if="'m.room.topic' === msg.type"> {{ members[msg.user_id].displayname || msg.user_id }} changed the topic to: {{ msg.content.topic }} </span> - <span ng-if="'m.room.name' === msg.type" ng-click="openJson(msg)"> + <span ng-if="'m.room.name' === msg.type"> {{ members[msg.user_id].displayname || msg.user_id }} changed the room name to: {{ msg.content.name }} </span> @@ -204,6 +257,9 @@ > Video Call </button> + <button ng-click="openRoomInfo()"> + Room Info + </button> </div> {{ feedback }}