Merge branch 'master' of github.com:matrix-org/synapse into sql_refactor

paul/schema_breaking_changes
Erik Johnston 2014-08-15 17:50:27 +01:00
commit 7f5c7ddea9
11 changed files with 173 additions and 28 deletions

View File

@ -694,6 +694,16 @@ Invite/Joining/Leaving a room
Required keys:
membership : [join|invite] - The membership state of $user_id in room
$room_id.
Optional keys:
displayname,
avatar_url : String fields from the member user's profile
state,
status_msg,
mtime_age : Presence information
These optional keys provide extra information that the client is likely to
be interested in so it doesn't have to perform an additional profile or
presence information fetch.
Where:
join - Indicate you ($user_id) are joining the room $room_id.

View File

@ -380,14 +380,23 @@ class PresenceHandler(BaseHandler):
logger.debug("Start polling for presence from %s", user)
if target_user:
target_users = [target_user]
target_users = set(target_user)
else:
presence = yield self.store.get_presence_list(
user.localpart, accepted=True
)
target_users = [
target_users = set([
self.hs.parse_userid(x["observed_user_id"]) for x in presence
]
])
# Also include people in all my rooms
rm_handler = self.homeserver.get_handlers().room_member_handler
room_ids = yield rm_handler.get_rooms_for_user(user)
for room_id in room_ids:
for member in (yield rm_handler.get_room_members(room_id)):
target_users.add(member)
if state is None:
state = yield self.store.get_presence_state(user.localpart)

View File

@ -22,7 +22,8 @@ var matrixWebClient = angular.module('matrixWebClient', [
'RoomsController',
'matrixService',
'eventStreamService',
'eventHandlerService'
'eventHandlerService',
'infinite-scroll'
]);
matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',

View File

@ -33,23 +33,24 @@ angular.module('eventHandlerService', [])
var PRESENCE_EVENT = "PRESENCE_EVENT";
$rootScope.events = {
rooms: {}, // will contain roomId: { messages:[], members:[] }
rooms: {}, // will contain roomId: { messages:[], members:{userid1: event} }
};
var initRoom = function(room_id) {
console.log("Creating new handler entry for " + room_id);
$rootScope.events.rooms[room_id] = {};
$rootScope.events.rooms[room_id].messages = [];
$rootScope.events.rooms[room_id].members = [];
if (!(room_id in $rootScope.events.rooms)) {
console.log("Creating new handler entry for " + room_id);
$rootScope.events.rooms[room_id] = {};
$rootScope.events.rooms[room_id].messages = [];
$rootScope.events.rooms[room_id].members = {};
}
}
var handleMessage = function(event, isLiveEvent) {
if ("membership_target" in event.content) {
event.user_id = event.content.membership_target;
}
if (!(event.room_id in $rootScope.events.rooms)) {
initRoom(event.room_id);
}
initRoom(event.room_id);
if (isLiveEvent) {
$rootScope.events.rooms[event.room_id].messages.push(event);
@ -67,6 +68,8 @@ angular.module('eventHandlerService', [])
};
var handleRoomMember = function(event, isLiveEvent) {
initRoom(event.room_id);
$rootScope.events.rooms[event.room_id].members[event.user_id] = event;
$rootScope.$broadcast(MEMBER_EVENT, event, isLiveEvent);
};

View File

@ -5,9 +5,11 @@
<link rel="stylesheet" href="app.css">
<link rel="icon" href="favicon.ico">
<script type='text/javascript' src='js/jquery-1.8.3.min.js'></script>
<script src="js/angular.js"></script>
<script src="js/angular-route.js"></script>
<script type='text/javascript' src='js/ng-infinite-scroll-matrix.js'></script>
<script src="app.js"></script>
<script src="app-controller.js"></script>
<script src="login/login-controller.js"></script>

2
webclient/js/jquery-1.8.3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,63 @@
/* ng-infinite-scroll - v1.0.0 - 2013-02-23
Matrix: Modified to support scrolling UP to get infinite loading and to listen
to scroll events on the PARENT element, not the window.
*/
var mod;
mod = angular.module('infinite-scroll', []);
mod.directive('infiniteScroll', [
'$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) {
return {
link: function(scope, elem, attrs) {
var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
$window = angular.element($window);
scrollDistance = 0;
if (attrs.infiniteScrollDistance != null) {
scope.$watch(attrs.infiniteScrollDistance, function(value) {
return scrollDistance = parseInt(value, 10);
});
}
scrollEnabled = true;
checkWhenEnabled = false;
if (attrs.infiniteScrollDisabled != null) {
scope.$watch(attrs.infiniteScrollDisabled, function(value) {
scrollEnabled = !value;
if (scrollEnabled && checkWhenEnabled) {
checkWhenEnabled = false;
return handler();
}
});
}
handler = function() {
var elementTop, remaining, shouldScroll, windowTop;
windowTop = 0;
elementTop = elem.offset().top;
shouldScroll = elementTop >= 0; // top of list is at the top of the window or further down the page
if (shouldScroll && scrollEnabled) {
if ($rootScope.$$phase) {
return scope.$eval(attrs.infiniteScroll);
} else {
return scope.$apply(attrs.infiniteScroll);
}
} else if (shouldScroll) {
return checkWhenEnabled = true;
}
};
elem.parent().on('scroll', handler);
scope.$on('$destroy', function() {
return elem.parent().off('scroll', handler);
});
return $timeout((function() {
if (attrs.infiniteScrollImmediateCheck) {
if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
return handler();
}
} else {
return handler();
}
}), 0);
}
};
}
]);

View File

@ -15,6 +15,32 @@ limitations under the License.
*/
angular.module('RoomController', [])
// FIXME move directives outta here!
.directive("keepScroll", function(){
return {
controller : function($scope){
var element = 0;
this.setElement = function(el){
element = el;
}
this.addItem = function(item){
element.scrollTop = (element.scrollTop+item.clientHeight+1); //1px for margin
};
},
link : function(scope,el,attr, ctrl) {
ctrl.setElement(el[0]);
}
};
})
// FIXME move directives outta here!
.directive("scrollItem", function(){
return{
require : "^keepScroll",
link : function(scope, el, att, scrCtrl){
scrCtrl.addItem(el[0]);
}
}
})
.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService',
function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService) {
'use strict';
@ -54,7 +80,14 @@ angular.module('RoomController', [])
updatePresence(event);
});
var paginate = function(numItems) {
$scope.paginateMore = function() {
if ($scope.state.can_paginate) {
console.log("Paginating more.");
paginate(MESSAGES_PER_PAGINATION, false);
}
};
var paginate = function(numItems, toBottom) {
matrixService.paginateBackMessages($scope.room_id, $scope.state.earliest_token, numItems).then(
function(response) {
eventHandlerService.handleEvents(response.data.chunk, false);
@ -63,6 +96,11 @@ angular.module('RoomController', [])
// no more messages to paginate :(
$scope.state.can_paginate = false;
}
if (toBottom) {
console.log("Scrolling to bottom");
scrollToBottom();
}
},
function(error) {
console.log("Failed to paginateBackMessages: " + JSON.stringify(error));
@ -73,6 +111,10 @@ angular.module('RoomController', [])
var updateMemberList = function(chunk) {
var isNewMember = !(chunk.target_user_id in $scope.members);
if (isNewMember) {
if ("state" in chunk.content) {
chunk.presenceState = chunk.content.state;
}
$scope.members[chunk.target_user_id] = chunk;
// get their display name and profile picture and set it to their
// member entry in $scope.members. We HAVE to use $timeout with 0 delay
@ -181,7 +223,7 @@ angular.module('RoomController', [])
}
);
paginate(MESSAGES_PER_PAGINATION);
paginate(MESSAGES_PER_PAGINATION, true);
},
function(reason) {
$scope.feedback = "Can't join room: " + reason;
@ -223,6 +265,6 @@ angular.module('RoomController', [])
};
$scope.loadMoreHistory = function() {
paginate(MESSAGES_PER_PAGINATION);
paginate(MESSAGES_PER_PAGINATION, false);
};
}]);

View File

@ -20,9 +20,9 @@
</table>
</div>
<div class="messageTableWrapper">
<table class="messageTable">
<tr ng-repeat="msg in events.rooms[room_id].messages" ng-class="msg.user_id === state.user_id ? 'mine' : ''">
<div class="messageTableWrapper" keep-scroll>
<table class="messageTable" infinite-scroll="paginateMore()">
<tr ng-repeat="msg in events.rooms[room_id].messages" ng-class="msg.user_id === state.user_id ? 'mine' : ''" scroll-item>
<td class="leftBlock">
<div class="sender" ng-hide="events.rooms[room_id].messages[$index - 1].user_id === msg.user_id">{{ members[msg.user_id].displayname || msg.user_id }}</div>
<div class="timestamp">{{ msg.content.hsob_ts | date:'MMM d HH:mm:ss' }}</div>

View File

@ -16,11 +16,11 @@ limitations under the License.
'use strict';
angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload'])
.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload',
function($scope, $location, matrixService, mFileUpload) {
angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService'])
.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService',
function($scope, $location, matrixService, mFileUpload, eventHandlerService) {
$scope.rooms = [];
$scope.rooms = {};
$scope.public_rooms = [];
$scope.newRoomId = "";
$scope.feedback = "";
@ -52,6 +52,18 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload']
linkedEmailList: matrixService.config().emailList // linked email list
};
$scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) {
var config = matrixService.config();
if (event.target_user_id === config.user_id && event.content.membership === "invite") {
console.log("Invited to room " + event.room_id);
// FIXME push membership to top level key to match /im/sync
event.membership = event.content.membership;
// FIXME bodge a nicer name than the room ID for this invite.
event.room_alias = event.user_id + "'s room";
$scope.rooms[event.room_id] = event;
}
});
var assignRoomAliases = function(data) {
for (var i=0; i<data.length; i++) {
var alias = matrixService.getRoomIdToAliasMapping(data[i].room_id);
@ -73,12 +85,13 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload']
$scope.refresh = function() {
// List all rooms joined or been invited to
$scope.rooms = matrixService.rooms();
matrixService.rooms().then(
function(response) {
var data = assignRoomAliases(response.data);
$scope.feedback = "Success";
$scope.rooms = data;
for (var i=0; i<data.length; i++) {
$scope.rooms[data[i].room_id] = data[i];
}
},
function(error) {
$scope.feedback = "Failure: " + error.data;

View File

@ -61,9 +61,9 @@
<h3>My rooms</h3>
<div class="rooms" ng-repeat="room in rooms">
<div class="rooms" ng-repeat="(rm_id, room) in rooms">
<div>
<a href="#/room/{{ room.room_id }}" >{{ room.room_alias }}</a>
<a href="#/room/{{ rm_id }}" >{{ room.room_alias }}</a> {{room.membership === 'invite' ? ' (invited)' : ''}}
</div>
</div>
<br/>
@ -86,7 +86,7 @@
</div>
<div>
<form>
<input size="40" ng-model="joinAlias.room_alias" ng-enter="joinAlias(joinAlias.room_alias)" placeholder="(e.g. #foo_channe:example.org)"/>
<input size="40" ng-model="joinAlias.room_alias" ng-enter="joinAlias(joinAlias.room_alias)" placeholder="(e.g. #foo_channel:example.org)"/>
<button ng-disabled="!joinAlias.room_alias" ng-click="joinAlias(joinAlias.room_alias)">Join room</button>
</form>
</div>