diff --git a/webclient/app.css b/webclient/app.css
index b9e7771ca8..869db69cd6 100644
--- a/webclient/app.css
+++ b/webclient/app.css
@@ -89,6 +89,7 @@ h1 {
height: 100px;
position: relative;
background-color: #000;
+ cursor: pointer;
}
.userAvatar .userAvatarImage {
@@ -251,6 +252,7 @@ h1 {
height: 160px;
display:table-cell;
vertical-align: middle;
+ text-align: center;
}
.profile-avatar img {
@@ -258,6 +260,14 @@ h1 {
max-height: 100%;
}
+/*** User profile page ***/
+#user-ids {
+ padding-left: 1em;
+}
+
+#user-displayname {
+ font-size: 16pt;
+}
/******************************/
#header {
diff --git a/webclient/app.js b/webclient/app.js
index 8d64db92d3..576912be46 100644
--- a/webclient/app.js
+++ b/webclient/app.js
@@ -20,6 +20,7 @@ var matrixWebClient = angular.module('matrixWebClient', [
'LoginController',
'RoomController',
'RoomsController',
+ 'UserController',
'matrixService',
'eventStreamService',
'eventHandlerService',
@@ -33,7 +34,13 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
templateUrl: 'login/login.html',
controller: 'LoginController'
}).
- when('/room/:room_id', {
+ when('/room/:room_id_or_alias', {
+ templateUrl: 'room/room.html',
+ controller: 'RoomController'
+ }).
+ when('/room/', { // room URL with room alias in it (ex: http://127.0.0.1:8000/#/room/#public:localhost:8080) will come here.
+ // The reason is that 2nd hash key breaks routeProvider parameters cutting so that the URL will not match with
+ // the previous '/room/:room_id_or_alias' URL rule
templateUrl: 'room/room.html',
controller: 'RoomController'
}).
@@ -41,6 +48,10 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider',
templateUrl: 'rooms/rooms.html',
controller: 'RoomsController'
}).
+ when('/user/:user_matrix_id', {
+ templateUrl: 'user/user.html',
+ controller: 'UserController'
+ }).
otherwise({
redirectTo: '/rooms'
});
diff --git a/webclient/components/fileInput/file-input-directive.js b/webclient/components/fileInput/file-input-directive.js
index 9b73f877e9..c5e4ae07a8 100644
--- a/webclient/components/fileInput/file-input-directive.js
+++ b/webclient/components/fileInput/file-input-directive.js
@@ -29,7 +29,7 @@ angular.module('mFileInput', [])
scope: {
selectedFile: '=mFileInput'
},
-
+
link: function(scope, element, attrs, ctrl) {
element.bind("click", function() {
element.find("input")[0].click();
@@ -38,6 +38,9 @@ angular.module('mFileInput', [])
scope.$apply();
});
});
+
+ // Change the mouse icon on mouseover on this element
+ element.css("cursor", "pointer");
}
};
});
\ No newline at end of file
diff --git a/webclient/components/fileUpload/file-upload-service.js b/webclient/components/fileUpload/file-upload-service.js
index 5729d5da48..d620e6a4d0 100644
--- a/webclient/components/fileUpload/file-upload-service.js
+++ b/webclient/components/fileUpload/file-upload-service.js
@@ -16,11 +16,12 @@
'use strict';
+// TODO determine if this is really required as a separate service to matrixService.
/*
* Upload an HTML5 file to a server
*/
angular.module('mFileUpload', [])
-.service('mFileUpload', ['$http', '$q', function ($http, $q) {
+.service('mFileUpload', ['matrixService', '$q', function (matrixService, $q) {
/*
* Upload an HTML5 file to a server and returned a promise
@@ -28,20 +29,19 @@ angular.module('mFileUpload', [])
*/
this.uploadFile = function(file) {
var deferred = $q.defer();
-
- // @TODO: This service runs with the do_POST hacky implementation of /synapse/demos/webserver.py.
- // This is temporary until we have a true file upload service
- console.log("Uploading " + file.name + "...");
- $http.post(file.name, file)
- .success(function(data, status, headers, config) {
- deferred.resolve(location.origin + data.url);
- console.log(" -> Successfully uploaded! Available at " + location.origin + data.url);
- }).
- error(function(data, status, headers, config) {
- console.log(" -> Failed to upload" + file.name);
- deferred.reject();
- });
+ console.log("Uploading " + file.name + "... to /matrix/content");
+ matrixService.uploadContent(file).then(
+ function(response) {
+ var content_url = location.origin + "/matrix/content/" + response.data.content_token;
+ console.log(" -> Successfully uploaded! Available at " + content_url);
+ deferred.resolve(content_url);
+ },
+ function(error) {
+ console.log(" -> Failed to upload " + file.name);
+ deferred.reject(error);
+ }
+ );
return deferred.promise;
};
-}]);
\ No newline at end of file
+}]);
diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js
index 3cd0aa674b..828396c866 100644
--- a/webclient/components/matrix/matrix-service.js
+++ b/webclient/components/matrix/matrix-service.js
@@ -54,13 +54,14 @@ angular.module('matrixService', [])
params.access_token = config.access_token;
+ if (path.indexOf(prefixPath) !== 0) {
+ path = prefixPath + path;
+ }
+
return doBaseRequest(config.homeserver, method, path, params, data, undefined);
};
var doBaseRequest = function(baseUrl, method, path, params, data, headers) {
- if (path.indexOf(prefixPath) !== 0) {
- path = prefixPath + path;
- }
return $http({
method: method,
url: baseUrl + path,
@@ -165,6 +166,16 @@ angular.module('matrixService', [])
return doRequest("DELETE", path, undefined, undefined);
},
+ // Retrieves the room ID corresponding to a room alias
+ resolveRoomAlias:function(room_alias) {
+ var path = "/matrix/client/api/v1/ds/room/$room_alias";
+ room_alias = encodeURIComponent(room_alias);
+
+ path = path.replace("$room_alias", room_alias);
+
+ return doRequest("GET", path, undefined, {});
+ },
+
sendMessage: function(room_id, msg_id, content) {
// The REST path spec
var path = "/rooms/$room_id/messages/$from/$msg_id";
@@ -309,6 +320,17 @@ angular.module('matrixService', [])
return doBaseRequest(config.identityServer, "POST", path, {}, data, headers);
},
+ uploadContent: function(file) {
+ var path = "/matrix/content";
+ var headers = {
+ "Content-Type": undefined // undefined means angular will figure it out
+ };
+ var params = {
+ access_token: config.access_token
+ };
+ return doBaseRequest(config.homeserver, "POST", path, params, file, headers);
+ },
+
// start listening on /events
getEventStream: function(from, timeout) {
var path = "/events";
diff --git a/webclient/index.html b/webclient/index.html
index 455eff4a13..51f6ff1f4d 100644
--- a/webclient/index.html
+++ b/webclient/index.html
@@ -16,6 +16,7 @@
<script src="login/login-controller.js"></script>
<script src="room/room-controller.js"></script>
<script src="rooms/rooms-controller.js"></script>
+ <script src="user/user-controller.js"></script>
<script src="components/matrix/matrix-service.js"></script>
<script src="components/matrix/event-stream-service.js"></script>
<script src="components/matrix/event-handler-service.js"></script>
diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js
index b859f3d7e8..b585e338ed 100644
--- a/webclient/room/room-controller.js
+++ b/webclient/room/room-controller.js
@@ -108,8 +108,11 @@ angular.module('RoomController', ['ngSanitize'])
function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService) {
'use strict';
var MESSAGES_PER_PAGINATION = 30;
- $scope.room_id = $routeParams.room_id;
- $scope.room_alias = matrixService.getRoomIdToAliasMapping($scope.room_id);
+
+ // Room ids. Computed and resolved in onInit
+ $scope.room_id = undefined;
+ $scope.room_alias = undefined;
+
$scope.state = {
user_id: matrixService.config().user_id,
events_from: "END", // when to start the event stream from.
@@ -144,7 +147,7 @@ angular.module('RoomController', ['ngSanitize'])
if (document.hidden) {
var notification = new window.Notification(
($scope.members[event.user_id].displayname || event.user_id) +
- " (" + $scope.room_alias + ")",
+ " (" + ($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,
@@ -342,7 +345,57 @@ angular.module('RoomController', ['ngSanitize'])
$scope.onInit = function() {
// $timeout(function() { document.getElementById('textInput').focus() }, 0);
console.log("onInit");
+
+ // Does the room ID provided in the URL?
+ var room_id_or_alias;
+ if ($routeParams.room_id_or_alias) {
+ room_id_or_alias = decodeURIComponent($routeParams.room_id_or_alias);
+ }
+
+ if (room_id_or_alias && '!' === room_id_or_alias[0]) {
+ // Yes. We can start right now
+ $scope.room_id = room_id_or_alias;
+ $scope.room_alias = matrixService.getRoomIdToAliasMapping($scope.room_id);
+ onInit2();
+ }
+ else {
+ // No. The URL contains the room alias. Get this alias.
+ if (room_id_or_alias) {
+ // The room alias was passed urlencoded, use it as is
+ $scope.room_alias = room_id_or_alias;
+ }
+ 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");
+ $location.path("/");
+ return;
+ }
+ }
+
+ // Need a room ID required in Matrix API requests
+ console.log("Resolving alias: " + $scope.room_alias);
+ matrixService.resolveRoomAlias($scope.room_alias).then(function(response) {
+ $scope.room_id = response.data.room_id;
+ console.log(" -> Room ID: " + $scope.room_id);
+
+ // Now, we can start
+ onInit2();
+ },
+ function () {
+ // In case of issue, go to the default page
+ console.log("Error: cannot resolve room alias");
+ $location.path("/");
+ });
+ }
+ };
+ var onInit2 = function() {
// Join the room
matrixService.join($scope.room_id).then(
function() {
@@ -380,6 +433,11 @@ angular.module('RoomController', ['ngSanitize'])
});
};
+ // Open the user profile page
+ $scope.goToUserPage = function(user_id) {
+ $location.url("/user/" + user_id);
+ };
+
$scope.leaveRoom = function() {
matrixService.leave($scope.room_id).then(
diff --git a/webclient/room/room.html b/webclient/room/room.html
index 106a9dfd15..36bd95c1bb 100644
--- a/webclient/room/room.html
+++ b/webclient/room/room.html
@@ -10,9 +10,13 @@
<div id="usersTableWrapper">
<table id="usersTable">
<tr ng-repeat="member in members | orderMembersList">
- <td class="userAvatar">
- <img class="userAvatarImage" ng-src="{{member.avatar_url || 'img/default-profile.jpg'}}" width="80" height="80"/>
- <img class="userAvatarGradient" src="img/gradient.png" width="80" height="24"/>
+ <td class="userAvatar" ng-click="goToUserPage(member.id)">
+ <img class="userAvatarImage"
+ ng-src="{{member.avatar_url || 'img/default-profile.jpg'}}"
+ alt="{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}"
+ title="{{ member.id }}"
+ width="80" height="80"/>
+ <img class="userAvatarGradient" src="img/gradient.png" title="{{ member.id }}" width="80" height="24"/>
<div class="userName">{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}<br/>{{ member.displayname ? "" : member.id.substr(member.id.indexOf(':')) }}</div>
</td>
<td class="userPresence" ng-class="member.presenceState === 'online' ? 'online' : (member.presenceState === 'unavailable' ? 'unavailable' : '')">
diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js
index da79c23d55..a237b59b4e 100644
--- a/webclient/rooms/rooms-controller.js
+++ b/webclient/rooms/rooms-controller.js
@@ -149,12 +149,8 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload',
$scope.joinAlias = function(room_alias) {
matrixService.joinAlias(room_alias).then(
function(response) {
- if (response.data.hasOwnProperty("room_id")) {
- $location.path("room/" + response.data.room_id);
- return;
- } else {
- // TODO (erikj): Do something here?
- }
+ // Go to this room
+ $location.path("room/" + room_alias);
},
function(error) {
$scope.feedback = "Can't join room: " + error.data;
diff --git a/webclient/rooms/rooms.html b/webclient/rooms/rooms.html
index 007ad29999..2602209bd3 100644
--- a/webclient/rooms/rooms.html
+++ b/webclient/rooms/rooms.html
@@ -65,7 +65,7 @@
<div class="rooms" ng-repeat="(rm_id, room) in rooms">
<div>
- <a href="#/room/{{ rm_id }}" >{{ room.room_alias }}</a> {{room.membership === 'invite' ? ' (invited)' : ''}}
+ <a href="#/room/{{ room.room_alias ? room.room_alias : rm_id }}" >{{ room.room_alias }}</a> {{room.membership === 'invite' ? ' (invited)' : ''}}
</div>
</div>
<br/>
@@ -74,7 +74,7 @@
<div class="public_rooms" ng-repeat="room in public_rooms">
<div>
- <a href="#/room/{{ room.room_id }}" >{{ room.room_alias }}</a>
+ <a href="#/room/{{ room.room_alias ? room.room_alias : room.room_id }}" >{{ room.room_alias }}</a>
</div>
</div>
<br/>
diff --git a/webclient/user/user-controller.js b/webclient/user/user-controller.js
new file mode 100644
index 0000000000..620230561c
--- /dev/null
+++ b/webclient/user/user-controller.js
@@ -0,0 +1,38 @@
+/*
+Copyright 2014 matrix.org
+
+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';
+
+angular.module('UserController', ['matrixService'])
+.controller('UserController', ['$scope', '$routeParams', 'matrixService',
+ function($scope, $routeParams, matrixService) {
+ $scope.user = {
+ id: $routeParams.user_matrix_id,
+ displayname: "",
+ avatar_url: undefined
+ };
+
+ matrixService.getDisplayName($scope.user.id).then(
+ function(response) {
+ $scope.user.displayname = response.data.displayname;
+ }
+ );
+ matrixService.getProfilePictureUrl($scope.user.id).then(
+ function(response) {
+ $scope.user.avatar_url = response.data.avatar_url;
+ }
+ );
+}]);
\ No newline at end of file
diff --git a/webclient/user/user.html b/webclient/user/user.html
new file mode 100644
index 0000000000..47db09d1ee
--- /dev/null
+++ b/webclient/user/user.html
@@ -0,0 +1,30 @@
+<div ng-controller="UserController" class="user">
+
+ <div id="page">
+ <div id="wrapper">
+
+ <div>
+ <form>
+ <table>
+ <tr>
+ <td>
+ <div class="profile-avatar">
+ <img ng-src="{{ user.avatar_url || 'img/default-profile.jpg' }}"/>
+ </div>
+ </td>
+ <td>
+ <div id="user-ids">
+ <div id="user-displayname">{{ user.displayname }}</div>
+ <div>{{ user.id }}</div>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </div>
+
+ {{ feedback }}
+
+ </div>
+ </div>
+</div>
|