2014-08-12 22:32:18 -04:00
/ *
2014-09-03 12:29:13 -04:00
Copyright 2014 OpenMarket Ltd
2014-08-12 22:32:18 -04:00
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 .
* /
2014-11-10 23:39:16 -05:00
angular . module ( 'RoomController' , [ 'ngSanitize' , 'matrixFilter' , 'mFileInput' , 'angular-peity' ] )
2014-11-14 06:13:03 -05:00
. controller ( 'RoomController' , [ '$modal' , '$filter' , '$scope' , '$timeout' , '$routeParams' , '$location' , '$rootScope' , 'matrixService' , 'mPresence' , 'eventHandlerService' , 'mFileUpload' , 'matrixPhoneService' , 'MatrixCall' , 'modelService' , 'recentsService' , 'commandsService' , 'mUserDisplayNameFilter' ,
function ( $modal , $filter , $scope , $timeout , $routeParams , $location , $rootScope , matrixService , mPresence , eventHandlerService , mFileUpload , matrixPhoneService , MatrixCall , modelService , recentsService , commandsService , mUserDisplayNameFilter ) {
2014-08-12 10:10:52 -04:00
'use strict' ;
2014-08-15 19:14:47 -04:00
var MESSAGES _PER _PAGINATION = 30 ;
2014-08-21 08:30:41 -04:00
var THUMBNAIL _SIZE = 320 ;
2014-10-31 07:20:07 -04:00
// .html needs this
2014-11-12 12:06:03 -05:00
$scope . containsBingWord = eventHandlerService . eventContainsBingWord ;
2014-08-18 11:11:08 -04:00
2014-08-18 11:40:05 -04:00
// Room ids. Computed and resolved in onInit
$scope . room _id = undefined ;
2014-08-18 11:11:08 -04:00
$scope . room _alias = undefined ;
2014-08-12 10:10:52 -04:00
$scope . state = {
user _id : matrixService . config ( ) . user _id ,
2014-09-11 10:54:51 -04:00
permission _denied : undefined , // If defined, this string contains the reason why the user cannot join the room
2014-08-21 10:27:15 -04:00
first _pagination : true , // this is toggled off when the first pagination is done
2014-09-09 10:46:30 -04:00
can _paginate : false , // this is toggled off when we are not ready yet to paginate or when we run out of items
2014-08-15 19:14:47 -04:00
paginating : false , // used to avoid concurrent pagination requests pulling in dup contents
2014-09-09 08:18:08 -04:00
stream _failure : undefined , // the response when the stream fails
2014-09-17 11:12:52 -04:00
waiting _for _joined _event : false , // true when the join request is pending. Back to false once the corresponding m.room.member event is received
2014-09-19 11:20:27 -04:00
messages _visibility : "hidden" , // In order to avoid flickering when scrolling down the message table at the page opening, delay the message table display
2014-08-12 10:10:52 -04:00
} ;
2014-08-13 05:42:28 -04:00
$scope . imageURLToSend = "" ;
2014-08-14 12:23:47 -04:00
2014-09-12 04:48:06 -04:00
// vars and functions for updating the name
$scope . name = {
isEditing : false ,
newNameText : "" ,
editName : function ( ) {
if ( $scope . name . isEditing ) {
console . log ( "Warning: Already editing name." ) ;
return ;
} ;
2014-10-31 13:13:27 -04:00
var nameEvent = $scope . room . current _room _state . state _events [ 'm.room.name' ] ;
2014-09-17 09:46:12 -04:00
if ( nameEvent ) {
$scope . name . newNameText = nameEvent . content . name ;
}
else {
$scope . name . newNameText = "" ;
}
2014-09-12 04:48:06 -04:00
// Force focus to the input
$timeout ( function ( ) {
angular . element ( '.roomNameInput' ) . focus ( ) ;
} , 0 ) ;
$scope . name . isEditing = true ;
} ,
updateName : function ( ) {
console . log ( "Updating name to " + $scope . name . newNameText ) ;
matrixService . setName ( $scope . room _id , $scope . name . newNameText ) . then (
function ( ) {
} ,
function ( error ) {
$scope . feedback = "Request failed: " + error . data . error ;
}
) ;
$scope . name . isEditing = false ;
} ,
cancelEdit : function ( ) {
$scope . name . isEditing = false ;
}
} ;
2014-09-08 21:40:34 -04:00
// vars and functions for updating the topic
$scope . topic = {
isEditing : false ,
newTopicText : "" ,
editTopic : function ( ) {
if ( $scope . topic . isEditing ) {
console . log ( "Warning: Already editing topic." ) ;
return ;
}
2014-10-31 13:13:27 -04:00
var topicEvent = $scope . room . current _room _state . state _events [ 'm.room.topic' ] ;
2014-09-08 21:59:26 -04:00
if ( topicEvent ) {
$scope . topic . newTopicText = topicEvent . content . topic ;
}
else {
$scope . topic . newTopicText = "" ;
}
2014-09-11 05:49:59 -04:00
// Force focus to the input
$timeout ( function ( ) {
angular . element ( '.roomTopicInput' ) . focus ( ) ;
} , 0 ) ;
2014-09-08 21:40:34 -04:00
$scope . topic . isEditing = true ;
} ,
updateTopic : function ( ) {
console . log ( "Updating topic to " + $scope . topic . newTopicText ) ;
2014-09-11 05:53:37 -04:00
matrixService . setTopic ( $scope . room _id , $scope . topic . newTopicText ) . then (
function ( ) {
} ,
function ( error ) {
$scope . feedback = "Request failed: " + error . data . error ;
}
) ;
2014-09-08 21:40:34 -04:00
$scope . topic . isEditing = false ;
} ,
cancelEdit : function ( ) {
$scope . topic . isEditing = false ;
}
2014-09-12 04:48:06 -04:00
} ;
2014-09-08 21:40:34 -04:00
2014-09-05 11:52:11 -04:00
var scrollToBottom = function ( force ) {
2014-08-16 17:05:31 -04:00
console . log ( "Scrolling to bottom" ) ;
2014-09-05 11:52:11 -04:00
// 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" ) ;
2014-10-29 07:03:58 -04:00
// 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 ) {
2014-09-05 11:52:11 -04:00
$timeout ( function ( ) {
objDiv . scrollTop = objDiv . scrollHeight ;
2014-09-17 11:12:52 -04:00
// Show the message table once the first scrolldown is done
if ( "visible" !== $scope . state . messages _visibility ) {
$timeout ( function ( ) {
$scope . state . messages _visibility = "visible" ;
} , 0 ) ;
}
2014-09-05 11:52:11 -04:00
} , 0 ) ;
}
2014-08-14 12:23:47 -04:00
} ;
2014-08-29 09:00:20 -04:00
2014-08-15 06:31:13 -04:00
$scope . $on ( eventHandlerService . MSG _EVENT , function ( ngEvent , event , isLive ) {
2014-08-15 07:51:20 -04:00
if ( isLive && event . room _id === $scope . room _id ) {
2014-09-05 11:52:11 -04:00
scrollToBottom ( ) ;
2014-08-14 12:23:47 -04:00
}
2014-08-15 06:31:13 -04:00
} ) ;
$scope . $on ( eventHandlerService . MEMBER _EVENT , function ( ngEvent , event , isLive ) {
2014-11-14 09:25:53 -05:00
// if there is a live event affecting us
if ( isLive && event . room _id === $scope . room _id && event . state _key === $scope . state . user _id ) {
2014-09-09 08:18:08 -04:00
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 ;
onInit3 ( ) ;
}
2014-11-14 09:25:53 -05:00
// if someone else changed our state..
else if ( event . user _id !== $scope . state . user _id && "invite" !== event . content . membership && "join" !== event . content . membership ) {
if ( "ban" === event . content . membership ) {
2014-11-14 06:13:03 -05:00
$scope . state . permission _denied = "You have been banned by " + mUserDisplayNameFilter ( event . user _id ) ;
2014-09-11 10:54:51 -04:00
}
else {
2014-11-14 06:13:03 -05:00
$scope . state . permission _denied = "You have been kicked by " + mUserDisplayNameFilter ( event . user _id ) ;
2014-09-17 03:41:21 -04:00
}
2014-09-11 10:54:51 -04:00
}
2014-09-09 08:18:08 -04:00
else {
scrollToBottom ( ) ;
}
2014-09-02 03:39:43 -04:00
}
2014-08-15 06:31:13 -04:00
} ) ;
2014-08-27 13:57:54 -04:00
2014-08-29 09:00:20 -04:00
$scope . memberCount = function ( ) {
2014-11-14 09:25:53 -05:00
return Object . keys ( $scope . room . now . members ) . length ;
2014-08-29 09:00:20 -04:00
} ;
2014-08-14 12:23:47 -04:00
2014-08-15 12:42:02 -04:00
$scope . paginateMore = function ( ) {
if ( $scope . state . can _paginate ) {
2014-08-15 19:14:47 -04:00
// console.log("Paginating more.");
2014-08-16 17:05:31 -04:00
paginate ( MESSAGES _PER _PAGINATION ) ;
2014-08-15 12:42:02 -04:00
}
} ;
2014-08-28 14:03:34 -04:00
2014-08-16 17:05:31 -04:00
var paginate = function ( numItems ) {
2014-09-13 06:35:36 -04:00
//console.log("paginate " + numItems + " and first_pagination is " + $scope.state.first_pagination);
2014-08-20 11:08:05 -04:00
if ( $scope . state . paginating || ! $scope . room _id ) {
2014-08-15 19:14:47 -04:00
return ;
}
else {
$scope . state . paginating = true ;
}
2014-09-10 06:01:00 -04:00
2014-10-31 12:22:15 -04:00
console . log ( "paginateBackMessages from " + $scope . room . old _room _state . pagination _token + " for " + numItems ) ;
2014-08-15 19:14:47 -04:00
var originalTopRow = $ ( "#messageTable>tbody>tr:first" ) [ 0 ] ;
2014-09-10 06:01:00 -04:00
// Paginate events from the point in cache
2014-10-31 12:22:15 -04:00
matrixService . paginateBackMessages ( $scope . room _id , $scope . room . old _room _state . pagination _token , numItems ) . then (
2014-08-14 12:23:47 -04:00
function ( response ) {
2014-09-10 06:01:00 -04:00
2014-09-16 09:03:07 -04:00
eventHandlerService . handleRoomMessages ( $scope . room _id , response . data , false , 'b' ) ;
2014-08-14 12:23:47 -04:00
if ( response . data . chunk . length < MESSAGES _PER _PAGINATION ) {
2014-08-15 19:14:47 -04:00
// no more messages to paginate. this currently never gets turned true again, as we never
// expire paginated contents in the current implementation.
2014-08-14 12:23:47 -04:00
$scope . state . can _paginate = false ;
}
2014-08-15 12:42:02 -04:00
2014-08-16 17:05:31 -04:00
$scope . state . paginating = false ;
var wrapper = $ ( "#messageTableWrapper" ) [ 0 ] ;
var table = $ ( "#messageTable" ) [ 0 ] ;
// console.log("wrapper height=" + wrapper.clientHeight + ", table scrollHeight=" + table.scrollHeight);
if ( $scope . state . can _paginate ) {
// check we don't have to pull in more messages
// n.b. we dispatch through a timeout() to allow the digest to run otherwise the .height methods are stale
$timeout ( function ( ) {
if ( table . scrollHeight < wrapper . clientHeight ) {
paginate ( MESSAGES _PER _PAGINATION ) ;
scrollToBottom ( ) ;
}
} , 0 ) ;
}
2014-08-21 10:27:15 -04:00
if ( $scope . state . first _pagination ) {
2014-09-13 06:35:36 -04:00
scrollToBottom ( true ) ;
2014-08-21 10:27:15 -04:00
$scope . state . first _pagination = false ;
2014-08-15 12:42:02 -04:00
}
2014-08-15 19:14:47 -04:00
else {
2014-08-16 17:05:31 -04:00
// lock the scroll position
2014-08-15 19:14:47 -04:00
$timeout ( function ( ) {
// FIXME: this risks a flicker before the scrollTop is actually updated, but we have to
// dispatch it into a function in order to first update the layout. The right solution
// might be to implement it as a directive, more like
// http://stackoverflow.com/questions/23736647/how-to-retain-scroll-position-of-ng-repeat-in-angularjs
// however, this specific solution breaks because it measures the rows height before
// the contents are interpolated.
2014-08-16 17:05:31 -04:00
wrapper . scrollTop = originalTopRow ? ( originalTopRow . offsetTop + wrapper . scrollTop ) : 0 ;
2014-08-15 19:14:47 -04:00
} , 0 ) ;
}
2014-08-14 12:23:47 -04:00
} ,
function ( error ) {
2014-08-14 12:40:27 -04:00
console . log ( "Failed to paginateBackMessages: " + JSON . stringify ( error ) ) ;
2014-08-15 19:14:47 -04:00
$scope . state . paginating = false ;
2014-08-14 12:23:47 -04:00
}
2014-08-20 11:08:05 -04:00
) ;
2014-08-14 12:23:47 -04:00
} ;
2014-08-29 12:21:57 -04:00
2014-11-14 09:25:53 -05:00
var updatePresenceTimes = function ( ) {
2014-08-29 12:21:57 -04:00
$scope . now = new Date ( ) . getTime ( ) ;
2014-08-29 12:54:11 -04:00
// TODO: don't bother polling every 5s if we know none of our counters are younger than 1 minute
2014-11-14 09:25:53 -05:00
$timeout ( updatePresenceTimes , 5 * 1000 ) ;
2014-08-29 07:30:20 -04:00
} ;
2014-08-12 10:10:52 -04:00
$scope . send = function ( ) {
2014-09-19 19:49:45 -04:00
var input = $ ( '#mainInput' ) . val ( ) ;
if ( undefined === input || input === "" ) {
2014-08-12 10:10:52 -04:00
return ;
}
2014-08-21 20:54:37 -04:00
2014-09-05 11:52:11 -04:00
scrollToBottom ( true ) ;
2014-09-17 08:18:39 -04:00
// Store the command in the history
2014-11-13 11:09:44 -05:00
$rootScope . $broadcast ( "commandHistory:BROADCAST_NEW_HISTORY_ITEM(item)" ,
input ) ;
2014-09-17 08:18:39 -04:00
2014-11-13 06:55:02 -05:00
var isEmote = input . indexOf ( "/me " ) === 0 ;
2014-11-13 06:58:28 -05:00
var promise ;
if ( ! isEmote ) {
promise = commandsService . processInput ( $scope . room _id , input ) ;
}
var echo = false ;
2014-09-03 05:07:44 -04:00
2014-11-13 06:55:02 -05:00
if ( ! promise ) { // not a non-echoable command
2014-09-06 13:13:38 -04:00
echo = true ;
2014-11-13 06:55:02 -05:00
if ( isEmote ) {
promise = matrixService . sendEmoteMessage ( $scope . room _id , input . substring ( 4 ) ) ;
}
else {
promise = matrixService . sendTextMessage ( $scope . room _id , input ) ;
}
2014-09-06 13:13:38 -04:00
}
if ( echo ) {
2014-09-05 08:09:14 -04:00
// Echo the message to the room
// To do so, create a minimalist fake text message event and add it to the in-memory list of room messages
var echoMessage = {
content : {
2014-11-13 06:55:02 -05:00
body : ( isEmote ? input . substring ( 4 ) : input ) ,
msgtype : ( isEmote ? "m.emote" : "m.text" ) ,
2014-09-05 08:09:14 -04:00
} ,
2014-10-17 18:11:55 -04:00
origin _server _ts : new Date ( ) . getTime ( ) , // fake a timestamp
2014-09-05 08:09:14 -04:00
room _id : $scope . room _id ,
type : "m.room.message" ,
user _id : $scope . state . user _id ,
2014-09-10 12:24:03 -04:00
echo _msg _state : "messagePending" // Add custom field to indicate the state of this fake message to HTML
2014-09-05 08:09:14 -04:00
} ;
2014-09-19 19:49:45 -04:00
$ ( '#mainInput' ) . val ( '' ) ;
2014-10-31 13:13:27 -04:00
$scope . room . addMessageEvent ( echoMessage ) ;
2014-09-05 08:09:14 -04:00
scrollToBottom ( ) ;
2014-08-12 10:10:52 -04:00
}
2014-09-04 12:40:15 -04:00
if ( promise ) {
2014-09-10 11:40:34 -04:00
// Reset previous feedback
$scope . feedback = "" ;
2014-09-04 12:40:15 -04:00
promise . then (
2014-09-10 12:24:03 -04:00
function ( response ) {
2014-09-04 12:40:15 -04:00
console . log ( "Request successfully sent" ) ;
2014-09-12 13:19:32 -04:00
2014-09-10 12:24:03 -04:00
if ( echo ) {
// Mark this fake message event with its allocated event_id
// When the true message event will come from the events stream (in handleMessage),
// we will be able to replace the fake one by the true one
echoMessage . event _id = response . data . event _id ;
2014-09-05 08:09:14 -04:00
}
else {
2014-09-19 19:49:45 -04:00
$ ( '#mainInput' ) . val ( '' ) ;
2014-09-10 12:24:03 -04:00
}
2014-09-04 12:40:15 -04:00
} ,
function ( error ) {
2014-11-13 06:55:02 -05:00
$scope . feedback = error . data . error ;
2014-09-05 08:09:14 -04:00
if ( echoMessage ) {
// Mark the message as unsent for the rest of the page life
2014-10-17 18:11:55 -04:00
echoMessage . origin _server _ts = "Unsent" ;
2014-09-05 08:09:14 -04:00
echoMessage . echo _msg _state = "messageUnSent" ;
}
2014-09-04 12:40:15 -04:00
} ) ;
}
2014-08-12 10:10:52 -04:00
} ;
2014-11-14 10:57:18 -05:00
// Tries to find a suitable room ID for this room.
2014-08-12 10:10:52 -04:00
$scope . onInit = function ( ) {
console . log ( "onInit" ) ;
2014-08-22 05:50:38 -04:00
2014-11-14 10:57:18 -05:00
// Try to find out the room ID to load.
2014-08-18 11:40:05 -04:00
var room _id _or _alias ;
2014-11-14 10:57:18 -05:00
if ( $routeParams . room _id _or _alias ) { // provided in the url
2014-08-18 11:40:05 -04:00
room _id _or _alias = decodeURIComponent ( $routeParams . room _id _or _alias ) ;
}
if ( room _id _or _alias && '!' === room _id _or _alias [ 0 ] ) {
2014-11-14 10:57:18 -05:00
// it's a room ID since they start with !
2014-08-18 11:40:05 -04:00
$scope . room _id = room _id _or _alias ;
2014-11-12 06:14:19 -05:00
$scope . room _alias = modelService . getRoomIdToAliasMapping ( $scope . room _id ) ;
2014-08-18 11:11:08 -04:00
onInit2 ( ) ;
}
else {
2014-11-14 10:57:18 -05:00
if ( room _id _or _alias && '#' === room _id _or _alias [ 0 ] ) {
2014-08-18 11:40:05 -04:00
$scope . room _alias = room _id _or _alias ;
2014-08-18 11:11:08 -04:00
}
2014-08-18 11:40:05 -04:00
else {
// Else get the room alias by hand from the URL
// ie: extract #public:localhost:8080 from http://127.0.0.1:8000/#/room/#public:localhost:8080
if ( 3 === location . hash . split ( "#" ) . length ) {
$scope . room _alias = "#" + location . hash . split ( "#" ) [ 2 ] ;
}
else {
// In case of issue, go to the default page
console . log ( "Error: cannot extract room alias" ) ;
2014-08-22 05:43:54 -04:00
$location . url ( "/" ) ;
2014-08-18 11:40:05 -04:00
return ;
}
2014-08-18 11:11:08 -04:00
}
// Need a room ID required in Matrix API requests
2014-08-18 11:40:05 -04:00
console . log ( "Resolving alias: " + $scope . room _alias ) ;
2014-08-18 11:11:08 -04:00
matrixService . resolveRoomAlias ( $scope . room _alias ) . then ( function ( response ) {
$scope . room _id = response . data . room _id ;
console . log ( " -> Room ID: " + $scope . room _id ) ;
2014-08-28 10:23:20 -04:00
// Now, we can go on
2014-08-18 11:11:08 -04:00
onInit2 ( ) ;
} ,
function ( ) {
// In case of issue, go to the default page
console . log ( "Error: cannot resolve room alias" ) ;
2014-08-22 05:43:54 -04:00
$location . url ( "/" ) ;
2014-08-18 11:11:08 -04:00
} ) ;
}
} ;
2014-08-28 10:23:20 -04:00
2014-08-18 11:11:08 -04:00
var onInit2 = function ( ) {
2014-10-31 12:22:15 -04:00
$scope . room = modelService . getRoom ( $scope . room _id ) ;
2014-08-28 10:23:20 -04:00
2014-09-16 10:13:24 -04:00
// Scroll down as soon as possible so that we point to the last message
// if it already exists in memory
scrollToBottom ( true ) ;
2014-08-28 10:23:20 -04:00
// Make sure the initialSync has been before going further
eventHandlerService . waitForInitialSyncCompletion ( ) . then (
2014-08-12 10:10:52 -04:00
function ( ) {
2014-11-14 10:57:18 -05:00
console . log ( "initialSync is complete." ) ;
2014-08-28 10:23:20 -04:00
var needsToJoin = true ;
// The room members is available in the data fetched by initialSync
2014-10-31 13:13:27 -04:00
if ( $scope . room ) {
2014-09-16 09:42:31 -04:00
2014-10-31 13:13:27 -04:00
var messages = $scope . room . events ;
2014-09-25 08:46:11 -04:00
if ( 0 === messages . length
|| ( 1 === messages . length && "m.room.member" === messages [ 0 ] . type && "invite" === messages [ 0 ] . content . membership && $scope . state . user _id === messages [ 0 ] . state _key ) ) {
// If we just joined a room, we won't have this history from initial sync, so we should try to paginate it anyway
$scope . state . first _pagination = true ;
2014-09-18 13:17:27 -04:00
}
else {
2014-09-25 08:46:11 -04:00
// There is no need to do a 1st pagination (initialSync provided enough to fill a page)
$scope . state . first _pagination = false ;
2014-09-18 13:17:27 -04:00
}
2014-09-16 09:42:31 -04:00
2014-10-31 13:13:27 -04:00
var members = $scope . room . current _room _state . members ;
2014-08-12 10:10:52 -04:00
2014-08-28 10:23:20 -04:00
// Check if the user has already join the room
if ( $scope . state . user _id in members ) {
2014-11-06 09:52:22 -05:00
if ( "join" === members [ $scope . state . user _id ] . event . content . membership ) {
2014-08-28 10:23:20 -04:00
needsToJoin = false ;
2014-08-12 10:10:52 -04:00
}
}
2014-08-28 10:23:20 -04:00
}
2014-08-14 12:23:47 -04:00
2014-08-28 10:23:20 -04:00
// Do we to join the room before starting?
if ( needsToJoin ) {
2014-09-09 08:18:08 -04:00
$scope . state . waiting _for _joined _event = true ;
2014-08-28 10:23:20 -04:00
matrixService . join ( $scope . room _id ) . then (
function ( ) {
2014-09-23 13:50:39 -04:00
// TODO: factor out the common housekeeping whenever we try to join a room or alias
matrixService . roomState ( $scope . room _id ) . then (
function ( response ) {
2014-09-23 15:01:11 -04:00
eventHandlerService . handleEvents ( response . data , false , true ) ;
2014-09-23 13:50:39 -04:00
} ,
function ( error ) {
console . error ( "Failed to get room state for: " + $scope . room _id ) ;
}
) ;
2014-09-09 08:18:08 -04:00
// onInit3 will be called once the joined m.room.member event is received from the events stream
// This avoids to get the joined information twice in parallel:
// - one from the events stream
// - one from the pagination because the pagination window covers this event ts
2014-08-28 10:23:20 -04:00
console . log ( "Joined room " + $scope . room _id ) ;
} ,
function ( reason ) {
2014-09-03 05:45:30 -04:00
console . log ( "Can't join room: " + JSON . stringify ( reason ) ) ;
2014-09-23 13:50:39 -04:00
// FIXME: what if it wasn't a perms problem?
2014-09-11 10:54:51 -04:00
$scope . state . permission _denied = "You do not have permission to join this room" ;
2014-08-28 10:23:20 -04:00
} ) ;
}
else {
onInit3 ( ) ;
}
}
) ;
} ;
var onInit3 = function ( ) {
console . log ( "onInit3" ) ;
// Make recents highlight the current room
2014-11-12 09:55:57 -05:00
recentsService . setSelectedRoomId ( $scope . room _id ) ;
2014-11-14 09:25:53 -05:00
updatePresenceTimes ( ) ;
2014-09-01 10:21:13 -04:00
2014-11-14 09:25:53 -05:00
// Allow pagination
$scope . state . can _paginate = true ;
2014-09-16 09:42:31 -04:00
2014-11-14 09:25:53 -05:00
// 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 ) ;
}
2014-08-12 10:10:52 -04:00
} ;
$scope . leaveRoom = function ( ) {
matrixService . leave ( $scope . room _id ) . then (
function ( response ) {
2014-09-23 20:12:59 -04:00
console . log ( "Left room " + $scope . room _id ) ;
2014-08-22 12:08:03 -04:00
$location . url ( "home" ) ;
2014-08-12 10:10:52 -04:00
} ,
2014-08-14 10:47:38 -04:00
function ( error ) {
$scope . feedback = "Failed to leave room: " + error . data . error ;
2014-08-12 10:10:52 -04:00
} ) ;
} ;
2014-08-20 10:18:50 -04:00
$scope . sendImage = function ( url , body ) {
2014-09-05 11:52:11 -04:00
scrollToBottom ( true ) ;
2014-08-20 10:18:50 -04:00
matrixService . sendImageMessage ( $scope . room _id , url , body ) . then (
2014-08-13 05:42:28 -04:00
function ( ) {
console . log ( "Image sent" ) ;
} ,
2014-08-14 10:47:38 -04:00
function ( error ) {
$scope . feedback = "Failed to send image: " + error . data . error ;
2014-08-13 05:42:28 -04:00
} ) ;
} ;
2014-08-14 12:23:47 -04:00
2014-08-14 12:53:05 -04:00
$scope . imageFileToSend ;
$scope . $watch ( "imageFileToSend" , function ( newValue , oldValue ) {
if ( $scope . imageFileToSend ) {
2014-08-21 08:30:41 -04:00
// Upload this image with its thumbnail to Internet
mFileUpload . uploadImageAndThumbnail ( $scope . imageFileToSend , THUMBNAIL _SIZE ) . then (
function ( imageMessage ) {
// imageMessage is complete message structure, send it as is
matrixService . sendMessage ( $scope . room _id , undefined , imageMessage ) . then (
function ( ) {
console . log ( "Image message sent" ) ;
2014-08-20 10:18:50 -04:00
} ,
function ( error ) {
2014-08-21 08:30:41 -04:00
$scope . feedback = "Failed to send image message: " + error . data . error ;
} ) ;
2014-08-14 12:53:05 -04:00
} ,
function ( error ) {
2014-08-21 08:30:41 -04:00
$scope . feedback = "Can't upload image" ;
2014-08-20 10:18:50 -04:00
}
2014-08-14 12:53:05 -04:00
) ;
}
} ) ;
2014-08-14 12:23:47 -04:00
$scope . loadMoreHistory = function ( ) {
2014-08-16 17:05:31 -04:00
paginate ( MESSAGES _PER _PAGINATION ) ;
2014-08-14 12:23:47 -04:00
} ;
2014-08-27 13:57:54 -04:00
2014-11-10 23:39:16 -05:00
$scope . checkWebRTC = function ( ) {
if ( ! $rootScope . isWebRTCSupported ( ) ) {
alert ( "Your browser does not support WebRTC" ) ;
return false ;
}
if ( $scope . memberCount ( ) != 2 ) {
alert ( "WebRTC calls are currently only supported on rooms with two members" ) ;
return false ;
}
return true ;
} ;
$scope . startVoiceCall = function ( ) {
if ( ! $scope . checkWebRTC ( ) ) return ;
2014-08-27 13:57:54 -04:00
var call = new MatrixCall ( $scope . room _id ) ;
2014-09-01 12:15:26 -04:00
call . onError = $rootScope . onCallError ;
call . onHangup = $rootScope . onCallHangup ;
2014-09-17 11:26:35 -04:00
// remote video element is used for playing audio in voice calls
2014-11-12 12:27:41 -05:00
call . remoteVideoSelector = angular . element ( '#remoteVideo' ) [ 0 ] ;
2014-09-17 11:26:35 -04:00
call . placeVoiceCall ( ) ;
2014-09-09 12:37:50 -04:00
$rootScope . currentCall = call ;
} ;
$scope . startVideoCall = function ( ) {
2014-11-10 23:39:16 -05:00
if ( ! $scope . checkWebRTC ( ) ) return ;
2014-09-09 12:37:50 -04:00
var call = new MatrixCall ( $scope . room _id ) ;
call . onError = $rootScope . onCallError ;
call . onHangup = $rootScope . onCallHangup ;
2014-11-07 12:56:28 -05:00
call . localVideoSelector = '#localVideo' ;
call . remoteVideoSelector = '#remoteVideo' ;
2014-09-17 11:26:35 -04:00
call . placeVideoCall ( ) ;
2014-09-01 12:15:26 -04:00
$rootScope . currentCall = call ;
2014-09-05 05:13:33 -04:00
} ;
2014-08-28 14:03:34 -04:00
2014-10-27 12:28:33 -04:00
$scope . openJson = function ( content ) {
2014-11-03 10:02:16 -05:00
$scope . event _selected = angular . copy ( content ) ;
// FIXME: Pre-calculated event data should be stripped in a nicer way.
2014-11-04 05:30:34 -05:00
$scope . event _selected . _ _room _member = undefined ;
$scope . event _selected . _ _target _room _member = undefined ;
2014-11-03 10:02:16 -05:00
2014-10-29 11:02:30 -04:00
// scope this so the template can check power levels and enable/disable
// buttons
2014-11-03 05:23:14 -05:00
$scope . pow = eventHandlerService . getUserPowerLevel ;
2014-10-29 11:02:30 -04:00
2014-10-27 12:28:33 -04:00
var modalInstance = $modal . open ( {
2014-10-29 11:02:30 -04:00
templateUrl : 'eventInfoTemplate.html' ,
controller : 'EventInfoController' ,
scope : $scope
2014-10-27 12:28:33 -04:00
} ) ;
2014-10-29 11:31:50 -04:00
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
} ) ;
2014-10-27 12:28:33 -04:00
} ;
2014-10-30 07:14:29 -04:00
$scope . openRoomInfo = function ( ) {
2014-10-30 13:01:17 -04:00
$scope . roomInfo = { } ;
$scope . roomInfo . newEvent = {
content : { } ,
type : "" ,
state _key : ""
} ;
2014-10-31 13:13:27 -04:00
var stateEvents = $scope . room . current _room _state . state _events ;
2014-10-30 12:21:27 -04:00
// 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.
2014-10-30 13:01:17 -04:00
$scope . roomInfo . stateEvents = JSON . parse ( JSON . stringify ( stateEvents ) ) ;
2014-10-30 07:14:29 -04:00
var modalInstance = $modal . open ( {
templateUrl : 'roomInfoTemplate.html' ,
controller : 'RoomInfoController' ,
size : 'lg' ,
scope : $scope
} ) ;
} ;
2014-10-29 11:02:30 -04:00
} ] )
. 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 ) +
2014-10-31 13:13:27 -04:00
" Redact level = " + $scope . room . current _room _state . state _events [ "m.room.ops_levels" ] . content . redact _level ) ;
2014-10-29 11:02:30 -04:00
console . log ( "Redact event >> " + JSON . stringify ( $scope . event _selected ) ) ;
2014-10-29 11:31:50 -04:00
$modalInstance . close ( "redact" ) ;
2014-10-29 11:02:30 -04:00
} ;
2014-11-12 06:40:19 -05:00
$scope . dismiss = $modalInstance . dismiss ;
2014-10-30 07:14:29 -04:00
} )
2014-10-30 12:31:47 -04:00
. controller ( 'RoomInfoController' , function ( $scope , $modalInstance , $filter , matrixService ) {
2014-10-30 07:14:29 -04:00
console . log ( "Displaying room info." ) ;
2014-11-12 12:06:03 -05:00
$scope . userIDToInvite = "" ;
$scope . inviteUser = function ( ) {
matrixService . invite ( $scope . room _id , $scope . userIDToInvite ) . then (
function ( ) {
console . log ( "Invited." ) ;
$scope . feedback = "Invite successfully sent to " + $scope . userIDToInvite ;
$scope . userIDToInvite = "" ;
} ,
function ( reason ) {
$scope . feedback = "Failure: " + reason . data . error ;
} ) ;
} ;
2014-10-30 07:14:29 -04:00
2014-10-30 09:24:40 -04:00
$scope . submit = function ( event ) {
2014-10-30 12:21:27 -04:00
if ( event . content ) {
2014-10-30 12:31:47 -04:00
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 ;
}
) ;
2014-10-30 12:21:27 -04:00
}
2014-10-30 09:24:40 -04:00
} ;
2014-10-30 07:14:29 -04:00
$scope . dismiss = $modalInstance . dismiss ;
2014-10-29 11:02:30 -04:00
} ) ;