From efe5aa6464200a69d3159c52e151a0131923f46d Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 13:35:04 +0200 Subject: Added resizeImage() --- .../components/utilities/utilities-service.js | 87 +++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/components/utilities/utilities-service.js b/webclient/components/utilities/utilities-service.js index fc0ee580dc..f9e52eacf8 100644 --- a/webclient/components/utilities/utilities-service.js +++ b/webclient/components/utilities/utilities-service.js @@ -22,7 +22,7 @@ angular.module('mUtilities', []) .service('mUtilities', ['$q', function ($q) { /* - * Gets the size of an image + * Get the size of an image * @param {File} imageFile the file containing the image * @returns {promise} A promise that will be resolved by an object with 2 members: * width & height @@ -50,4 +50,89 @@ angular.module('mUtilities', []) return deferred.promise; }; + + /* + * Resize the image to fit in a square of the side maxSize. + * The aspect ratio is kept. The returned image data uses JPEG compression. + * Source: http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/ + * @param {File} imageFile the file containing the image + * @param {Integer} maxSize the max side size + * @returns {promise} A promise that will be resolved by a Blob object containing + * the resized image data + */ + this.resizeImage = function(imageFile, maxSize) { + var self = this; + var deferred = $q.defer(); + + var canvas = document.createElement("canvas"); + + var img = document.createElement("img"); + var reader = new FileReader(); + reader.onload = function(e) { + + img.src = e.target.result; + + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); + + var MAX_WIDTH = maxSize; + var MAX_HEIGHT = maxSize; + var width = img.width; + var height = img.height; + + if (width > height) { + if (width > MAX_WIDTH) { + height *= MAX_WIDTH / width; + width = MAX_WIDTH; + } + } else { + if (height > MAX_HEIGHT) { + width *= MAX_HEIGHT / height; + height = MAX_HEIGHT; + } + } + canvas.width = width; + canvas.height = height; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, width, height); + + var dataUrl = canvas.toDataURL("image/jpeg", 0.7); + deferred.resolve(self.dataURItoBlob(dataUrl)); + }; + reader.onerror = function(e) { + deferred.reject(e); + }; + reader.readAsDataURL(imageFile); + + return deferred.promise; + }; + + /* + * Convert a dataURI string to a blob + * Source: http://stackoverflow.com/a/17682951 + * @param {String} dataURI the dataURI can be a base64 encoded string or an URL encoded string. + * @returns {Blob} the blob + */ + this.dataURItoBlob = function(dataURI) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs + var byteString; + if (dataURI.split(',')[0].indexOf('base64') >= 0) + byteString = atob(dataURI.split(',')[1]); + else + byteString = unescape(dataURI.split(',')[1]); + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + // write the ArrayBuffer to a blob, and you're done + return new Blob([ab],{type: mimeString}); + }; + }]); \ No newline at end of file -- cgit 1.4.1 From 9d4bc8985f72ffffedd510eaa39b2bd5dc71f9ed Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 13:36:14 +0200 Subject: Made uploadContent compatible for sending Blob objects --- webclient/components/matrix/matrix-service.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'webclient') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index cd37a0c234..fa5a6091d3 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -61,14 +61,22 @@ angular.module('matrixService', []) return doBaseRequest(config.homeserver, method, path, params, data, undefined); }; - var doBaseRequest = function(baseUrl, method, path, params, data, headers) { - return $http({ + var doBaseRequest = function(baseUrl, method, path, params, data, headers, $httpParams) { + + var request = { method: method, url: baseUrl + path, params: params, data: data, headers: headers - }); + }; + + // Add additional $http parameters + if ($httpParams) { + angular.extend(request, $httpParams); + } + + return $http(request); }; @@ -326,7 +334,17 @@ angular.module('matrixService', []) var params = { access_token: config.access_token }; - return doBaseRequest(config.homeserver, "POST", path, params, file, headers); + + // If the file is actually a Blob object, prevent $http from JSON-stringified it before sending + // (Equivalent to jQuery ajax processData = false) + var $httpParams; + if (file instanceof Blob) { + $httpParams = { + transformRequest: angular.identity + }; + } + + return doBaseRequest(config.homeserver, "POST", path, params, file, headers, $httpParams); }, // start listening on /events -- cgit 1.4.1 From aac52fce15a592ac0715f72864f144600e4c15a1 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 14:30:41 +0200 Subject: Generate thumbnail client side and send its URL and info with the image message body --- .../components/fileUpload/file-upload-service.js | 141 ++++++++++++++++++++- .../components/utilities/utilities-service.js | 2 +- webclient/room/room-controller.js | 34 ++--- 3 files changed, 149 insertions(+), 28 deletions(-) (limited to 'webclient') diff --git a/webclient/components/fileUpload/file-upload-service.js b/webclient/components/fileUpload/file-upload-service.js index 65c24f309c..6606f31e22 100644 --- a/webclient/components/fileUpload/file-upload-service.js +++ b/webclient/components/fileUpload/file-upload-service.js @@ -20,17 +20,18 @@ /* * Upload an HTML5 file to a server */ -angular.module('mFileUpload', []) -.service('mFileUpload', ['matrixService', '$q', function (matrixService, $q) { +angular.module('mFileUpload', ['matrixService', 'mUtilities']) +.service('mFileUpload', ['$q', 'matrixService', 'mUtilities', function ($q, matrixService, mUtilities) { /* - * Upload an HTML5 file to a server and returned a promise + * Upload an HTML5 file or blob to a server and returned a promise * that will provide the URL of the uploaded file. + * @param {File|Blob} file the file data to send */ - this.uploadFile = function(file, body) { + this.uploadFile = function(file) { var deferred = $q.defer(); console.log("Uploading " + file.name + "... to /matrix/content"); - matrixService.uploadContent(file, body).then( + 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); @@ -44,4 +45,134 @@ angular.module('mFileUpload', []) return deferred.promise; }; + + /* + * Upload an image file plus generate a thumbnail of it and upload it so that + * we will have all information to fulfill an image message request data. + * @param {File} imageFile the imageFile to send + * @param {Integer} thumbnailSize the max side size of the thumbnail to create + * @returns {promise} A promise that will be resolved by a image message object + * ready to be send with the Matrix API + */ + this.uploadImageAndThumbnail = function(imageFile, thumbnailSize) { + var self = this; + var deferred = $q.defer(); + + console.log("uploadImageAndThumbnail " + imageFile.name + " - thumbnailSize: " + thumbnailSize); + + // The message structure that will be returned in the promise + var imageMessage = { + msgtype: "m.image", + url: undefined, + body: { + size: undefined, + w: undefined, + h: undefined, + mimetype: undefined + }, + thumbnail_url: undefined, + thumbnail_info: { + size: undefined, + w: undefined, + h: undefined, + mimetype: undefined + } + }; + + // First, get the image size + mUtilities.getImageSize(imageFile).then( + function(size) { + + // The final operation: send imageFile + var uploadImage = function() { + self.uploadFile(imageFile).then( + function(url) { + // Update message metadata + imageMessage.url = url; + imageMessage.body = { + size: imageFile.size, + w: size.width, + h: size.height, + mimetype: imageFile.type + }; + + // If there is no thumbnail (because the original image is smaller than thumbnailSize), + // reuse the original image info for thumbnail data + if (!imageMessage.thumbnail_url) { + imageMessage.thumbnail_url = imageMessage.url; + imageMessage.thumbnail_info = imageMessage.body; + } + + // We are done + deferred.resolve(imageMessage); + }, + function(error) { + console.log(" -> Can't upload image"); + deferred.reject(error); + } + ); + }; + + // Create a thumbnail if the image size exceeds thumbnailSize + if (Math.max(size.width, size.height) > thumbnailSize) { + console.log(" Creating thumbnail..."); + mUtilities.resizeImage(imageFile, thumbnailSize).then( + function(thumbnailBlob) { + + // Get its size + mUtilities.getImageSize(thumbnailBlob).then( + function(thumbnailSize) { + console.log(" -> Thumbnail size: " + JSON.stringify(thumbnailSize)); + + // Upload it to the server + self.uploadFile(thumbnailBlob).then( + function(thumbnailUrl) { + + // Update image message data + imageMessage.thumbnail_url = thumbnailUrl; + imageMessage.thumbnail_info = { + size: thumbnailBlob.size, + w: thumbnailSize.width, + h: thumbnailSize.height, + mimetype: thumbnailBlob.type + }; + + // Then, upload the original image + uploadImage(); + }, + function(error) { + console.log(" -> Can't upload thumbnail"); + deferred.reject(error); + } + ); + }, + function(error) { + console.log(" -> Failed to get thumbnail size"); + deferred.reject(error); + } + ); + + }, + function(error) { + console.log(" -> Failed to create thumbnail: " + error); + deferred.reject(error); + } + ); + } + else { + // No need of thumbnail + console.log(" Thumbnail is not required"); + uploadImage(); + } + + }, + function(error) { + console.log(" -> Failed to get image size"); + deferred.reject(error); + } + ); + + return deferred.promise; + }; + }]); diff --git a/webclient/components/utilities/utilities-service.js b/webclient/components/utilities/utilities-service.js index f9e52eacf8..9cf858ef39 100644 --- a/webclient/components/utilities/utilities-service.js +++ b/webclient/components/utilities/utilities-service.js @@ -23,7 +23,7 @@ angular.module('mUtilities', []) .service('mUtilities', ['$q', function ($q) { /* * Get the size of an image - * @param {File} imageFile the file containing the image + * @param {File|Blob} imageFile the file containing the image * @returns {promise} A promise that will be resolved by an object with 2 members: * width & height */ diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 35abeeca06..7de50dd960 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -19,6 +19,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService, mFileUpload, mUtilities) { 'use strict'; var MESSAGES_PER_PAGINATION = 30; + var THUMBNAIL_SIZE = 320; // Room ids. Computed and resolved in onInit $scope.room_id = undefined; @@ -386,33 +387,22 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) $scope.state.sending = true; - // First, get the image sise - mUtilities.getImageSize($scope.imageFileToSend).then( - function(size) { - - // Upload the image to the Internet - console.log("Uploading image..."); - mFileUpload.uploadFile($scope.imageFileToSend).then( - function(url) { - // Build the image info data - var imageInfo = { - size: $scope.imageFileToSend.size, - mimetype: $scope.imageFileToSend.type, - w: size.width, - h: size.height - }; - - // Then share the URL and the metadata - $scope.sendImage(url, imageInfo); + // 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"); + $scope.state.sending = false; }, function(error) { - $scope.feedback = "Can't upload image"; + $scope.feedback = "Failed to send image message: " + error.data.error; $scope.state.sending = false; - } - ); + }); }, function(error) { - $scope.feedback = "Can't get selected image size"; + $scope.feedback = "Can't upload image"; $scope.state.sending = false; } ); -- cgit 1.4.1 From e4f0e1af1aa075e6d86921d46e824d85855c1def Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 14:58:26 +0200 Subject: If there are available, show image thumbnails in the messages list --- webclient/room/room.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'webclient') diff --git a/webclient/room/room.html b/webclient/room/room.html index db6add4ee7..5dcc8caa1e 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -41,9 +41,13 @@
-
- +
+
+ +
+
+ +
-- cgit 1.4.1 From bb4490c2d78d4e0dcae01853513e0308776055a5 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 16:09:42 +0200 Subject: Show image fullscreen when clicking on the thumbnail --- webclient/app.css | 25 ++++++++++++++++++++++++- webclient/room/room.html | 9 +++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index 869db69cd6..d2b951d3b6 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -66,6 +66,10 @@ h1 { background-color: #faa; } +.mouse-pointer { + cursor: pointer; +} + /*** Participant list ***/ #usersTableWrapper { @@ -89,7 +93,6 @@ h1 { height: 100px; position: relative; background-color: #000; - cursor: pointer; } .userAvatar .userAvatarImage { @@ -245,6 +248,26 @@ h1 { text-align: left ! important; } +#room-fullscreen-image { + position: absolute; + top: 0px; + height: 0px; + width: 100%; + height: 100%; +} + +#room-fullscreen-image img { + max-width: 100%; + max-height: 100%; + bottom: 0; + left: 0; + margin: auto; + overflow: auto; + position: fixed; + right: 0; + top: 0; +} + /*** Profile ***/ .profile-avatar { diff --git a/webclient/room/room.html b/webclient/room/room.html index 5dcc8caa1e..cb9cf1d1f3 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -10,7 +10,7 @@
-
+ {{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}
- +
@@ -96,4 +97,8 @@ +
+ +
+ -- cgit 1.4.1 From 01a129cb9a3dea54faf65bea4cf10dee22b55fde Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 21 Aug 2014 15:26:19 +0100 Subject: cheer up erik and remove the double-horizontal-border between adjacent text plinths --- webclient/app.css | 1 + 1 file changed, 1 insertion(+) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index 869db69cd6..1717b1b355 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -192,6 +192,7 @@ h1 { border: 1px solid #d8d8d8; height: 31px; display: inline-table; + margin-top: -1px; max-width: 90%; font-size: 16px; /* word-wrap: break-word; */ -- cgit 1.4.1 From 14b99896604c8860ebb2a6ed607fae40fe04494b Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Thu, 21 Aug 2014 16:27:15 +0200 Subject: Fixed first pagination detection --- webclient/room/room-controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'webclient') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 35abeeca06..6d714151f1 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -28,6 +28,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) user_id: matrixService.config().user_id, events_from: "END", // when to start the event stream from. earliest_token: "END", // stores how far back we've paginated. + first_pagination: true, // this is toggled off when the first pagination is done can_paginate: true, // this is toggled off when we run out of items paginating: false, // used to avoid concurrent pagination requests pulling in dup contents stream_failure: undefined, // the response when the stream fails @@ -99,7 +100,6 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) var originalTopRow = $("#messageTable>tbody>tr:first")[0]; matrixService.paginateBackMessages($scope.room_id, $scope.state.earliest_token, numItems).then( function(response) { - var firstPagination = !$scope.events.rooms[$scope.room_id]; eventHandlerService.handleEvents(response.data.chunk, false); $scope.state.earliest_token = response.data.end; if (response.data.chunk.length < MESSAGES_PER_PAGINATION) { @@ -125,8 +125,9 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) }, 0); } - if (firstPagination) { + if ($scope.state.first_pagination) { scrollToBottom(); + $scope.state.first_pagination = false; } else { // lock the scroll position -- cgit 1.4.1 From 4c228df167ca1708964c93c3c20e46d631899ce1 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Aug 2014 15:30:57 +0100 Subject: Use the new 'inviter' key from im sync for room display names. --- webclient/rooms/rooms-controller.js | 9 +++++++-- webclient/rooms/rooms.html | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'webclient') diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index c25e24c8bc..f2ff4a25ba 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -59,7 +59,7 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', // 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"; + event.room_display_name = event.user_id + "'s room"; $scope.rooms[event.room_id] = event; } }); @@ -70,15 +70,20 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', if (alias) { // use the existing alias from storage data[i].room_alias = alias; + data[i].room_display_name = alias; } else if (data[i].aliases && data[i].aliases[0]) { // save the mapping // TODO: select the smarter alias from the array matrixService.createRoomIdToAliasMapping(data[i].room_id, data[i].aliases[0]); + data[i].room_display_name = data[i].aliases[0]; + } + else if (data[i].membership == "invite" && "inviter" in data[i]) { + data[i].room_display_name = data[i].inviter + "'s room" } else { // last resort use the room id - data[i].room_alias = data[i].room_id; + data[i].room_display_name = data[i].room_id; } } return data; diff --git a/webclient/rooms/rooms.html b/webclient/rooms/rooms.html index 2602209bd3..ba3b7d8bad 100644 --- a/webclient/rooms/rooms.html +++ b/webclient/rooms/rooms.html @@ -65,7 +65,7 @@
- {{ room.room_alias }} {{room.membership === 'invite' ? ' (invited)' : ''}} + {{ room.room_display_name }} {{room.membership === 'invite' ? ' (invited)' : ''}}

-- cgit 1.4.1 From ad869fa4b30d660bb3307e8bdab26c36c52a7221 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 21 Aug 2014 15:43:47 +0100 Subject: stop hammering the HS for displayname and avatar URLs --- webclient/room/room-controller.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'webclient') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 8dea64a804..eee805dafb 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -160,8 +160,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) if ("mtime_age" in chunk.content) { chunk.mtime_age = chunk.content.mtime_age; } -/* - // FIXME: once the HS reliably returns the displaynames & avatar_urls for both + // Once the HS reliably returns the displaynames & avatar_urls for both // local and remote users, we should use this rather than the evalAsync block // below if ("displayname" in chunk.content) { @@ -170,9 +169,11 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) if ("avatar_url" in chunk.content) { chunk.avatar_url = chunk.content.avatar_url; } - */ $scope.members[chunk.target_user_id] = chunk; +/* + // Stale code for explicitly hammering the homeserver for every displayname & avatar_url + // 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 // to make this function run AFTER the current digest cycle, else the @@ -196,6 +197,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) } ); }); +*/ } else { // selectively update membership else it will nuke the picture and displayname too :/ -- cgit 1.4.1 From 7dac1bfc9148e4e23d388d8281aacee2bb41d5db Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Aug 2014 17:17:41 +0100 Subject: Change webclient to always hit the im sync api before streaming so we get current presence state --- .../components/matrix/event-stream-service.js | 41 ++++++++++++++++++---- webclient/rooms/rooms-controller.js | 7 +++- 2 files changed, 41 insertions(+), 7 deletions(-) (limited to 'webclient') diff --git a/webclient/components/matrix/event-stream-service.js b/webclient/components/matrix/event-stream-service.js index a446fad5d4..9a8f6eac4c 100644 --- a/webclient/components/matrix/event-stream-service.js +++ b/webclient/components/matrix/event-stream-service.js @@ -48,11 +48,12 @@ angular.module('eventStreamService', []) var saveStreamSettings = function() { localStorage.setItem("streamSettings", JSON.stringify(settings)); }; - - var startEventStream = function() { + + var doEventStream = function(deferred) { settings.shouldPoll = true; settings.isActive = true; - var deferred = $q.defer(); + deferred = deferred || $q.defer(); + // run the stream from the latest token matrixService.getEventStream(settings.from, TIMEOUT_MS).then( function(response) { @@ -63,13 +64,16 @@ angular.module('eventStreamService', []) settings.from = response.data.end; - console.log("[EventStream] Got response from "+settings.from+" to "+response.data.end); + console.log( + "[EventStream] Got response from "+settings.from+ + " to "+response.data.end + ); eventHandlerService.handleEvents(response.data.chunk, true); deferred.resolve(response); if (settings.shouldPoll) { - $timeout(startEventStream, 0); + $timeout(doEventStream, 0); } else { console.log("[EventStream] Stopping poll."); @@ -83,13 +87,38 @@ angular.module('eventStreamService', []) deferred.reject(error); if (settings.shouldPoll) { - $timeout(startEventStream, ERR_TIMEOUT_MS); + $timeout(doEventStream, ERR_TIMEOUT_MS); } else { console.log("[EventStream] Stopping polling."); } } ); + + return deferred.promise; + } + + var startEventStream = function() { + settings.shouldPoll = true; + settings.isActive = true; + var deferred = $q.defer(); + + // FIXME: We are discarding all the messages. + matrixService.rooms().then( + function(response) { + var presence = response.data.presence; + for (var i = 0; i < presence.length; ++i) { + eventHandlerService.handleEvent(presence[i], false); + } + + settings.from = response.data.end + doEventStream(deferred); + }, + function(error) { + $scope.feedback = "Failure: " + error.data; + } + ); + return deferred.promise; }; diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index f2ff4a25ba..6bbb2b2ba1 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -93,11 +93,16 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', // List all rooms joined or been invited to matrixService.rooms().then( function(response) { - var data = assignRoomAliases(response.data); + var data = assignRoomAliases(response.data.rooms); $scope.feedback = "Success"; for (var i=0; i Date: Thu, 21 Aug 2014 17:55:41 +0100 Subject: Only start event streaming after having set up the controllers. --- demo/start.sh | 3 ++- webclient/app-controller.js | 2 +- webclient/app.js | 2 +- webclient/components/matrix/event-stream-service.js | 10 ++++++++++ webclient/room/room-controller.js | 1 + webclient/rooms/rooms-controller.js | 6 ++++-- 6 files changed, 19 insertions(+), 5 deletions(-) (limited to 'webclient') diff --git a/demo/start.sh b/demo/start.sh index 4701872926..fa2998a5e9 100755 --- a/demo/start.sh +++ b/demo/start.sh @@ -15,7 +15,8 @@ for port in "8080" "8081" "8082"; do -f "$DIR/$port.log" \ -d "$DIR/$port.db" \ -vv \ - -D --pid-file "$DIR/$port.pid" + -D --pid-file "$DIR/$port.pid"\ + -w done echo "Starting webclient on port 8000..." diff --git a/webclient/app-controller.js b/webclient/app-controller.js index 96656e12c3..c53f29aa77 100644 --- a/webclient/app-controller.js +++ b/webclient/app-controller.js @@ -53,7 +53,7 @@ angular.module('MatrixWebClientController', ['matrixService']) }; if (matrixService.isUserLoggedIn()) { - eventStreamService.resume(); + // eventStreamService.resume(); } // Logs the user out diff --git a/webclient/app.js b/webclient/app.js index f27ebedc6f..944b8ec270 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -80,6 +80,6 @@ matrixWebClient.run(['$location', 'matrixService', 'eventStreamService', functio $location.path("login"); } else { - eventStreamService.resume(); + // eventStreamService.resume(); } }]); diff --git a/webclient/components/matrix/event-stream-service.js b/webclient/components/matrix/event-stream-service.js index 9a8f6eac4c..a1a98b2a36 100644 --- a/webclient/components/matrix/event-stream-service.js +++ b/webclient/components/matrix/event-stream-service.js @@ -106,6 +106,16 @@ angular.module('eventStreamService', []) // FIXME: We are discarding all the messages. matrixService.rooms().then( function(response) { + var rooms = response.data.rooms; + for (var i = 0; i < rooms.length; ++i) { + var room = rooms[i]; + if ("state" in room) { + for (var j = 0; j < room.state.length; ++j) { + eventHandlerService.handleEvents(room.state[j], false); + } + } + } + var presence = response.data.presence; for (var i = 0; i < presence.length; ++i) { eventHandlerService.handleEvent(presence[i], false); diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index eee805dafb..214166a434 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -328,6 +328,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) var chunk = response.data.chunk[i]; updateMemberList(chunk); } + eventStreamService.resume(); }, function(error) { $scope.feedback = "Failed get member list: " + error.data.error; diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index 6bbb2b2ba1..c2d7bcb6f3 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -17,8 +17,8 @@ limitations under the License. 'use strict'; angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) -.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', - function($scope, $location, matrixService, mFileUpload, eventHandlerService) { +.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', + function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { $scope.rooms = {}; $scope.public_rooms = []; @@ -113,6 +113,8 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', $scope.public_rooms = assignRoomAliases(response.data.chunk); } ); + + eventStreamService.resume(); }; $scope.createNewRoom = function(room_id, isPrivate) { -- cgit 1.4.1 From 0045a2647ad3e0e088dacbee8497dbbb7d118269 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Aug 2014 17:59:07 +0100 Subject: Add a var. --- webclient/app-filter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/app-filter.js b/webclient/app-filter.js index 64c3bb04de..f007b4c89c 100644 --- a/webclient/app-filter.js +++ b/webclient/app-filter.js @@ -58,7 +58,7 @@ angular.module('matrixWebClient') angular.forEach(displayNames, function(value, key) { if (value.length > 1) { // console.log(key + ": " + value); - for (i=0; i < value.length; i++) { + for (var i=0; i < value.length; i++) { var v = value[i]; members[v].displayname += " (" + v + ")"; // console.log(v + " " + members[v]); -- cgit 1.4.1 From 3277a650529d4ecaf816987e6cbcb87fdf3371da Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 21 Aug 2014 19:02:00 +0100 Subject: actually display room metadata based on m.room.membe events --- webclient/app.css | 4 ++++ webclient/components/matrix/event-handler-service.js | 11 +++++++++++ webclient/room/room.html | 10 ++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index 83b0c9c65a..a63b5db4d6 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -245,6 +245,10 @@ h1 { background-color: #fff ! important; } +.mine .membership { + background-color: #fff ! important; +} + .mine .text .bubble { text-align: left ! important; } diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index b8529895fe..6a01b3fb55 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -69,6 +69,17 @@ angular.module('eventHandlerService', []) var handleRoomMember = function(event, isLiveEvent) { initRoom(event.room_id); + + // add membership changes as if they were a room message if something interesting changed + if (event.content.prev !== event.content.membership) { + if (isLiveEvent) { + $rootScope.events.rooms[event.room_id].messages.push(event); + } + else { + $rootScope.events.rooms[event.room_id].messages.unshift(event); + } + } + $rootScope.events.rooms[event.room_id].members[event.user_id] = event; $rootScope.$broadcast(MEMBER_EVENT, event, isLiveEvent); }; diff --git a/webclient/room/room.html b/webclient/room/room.html index cb9cf1d1f3..4a07dfdaaf 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -26,19 +26,25 @@
+ -
{{ members[msg.user_id].displayname || msg.user_id }}
-
{{ msg.content.hsob_ts | date:'MMM d HH:mm:ss' }}
+
{{ (msg.content.hsob_ts || msg.ts) | date:'MMM d HH:mm:ss' }}
+
+ + {{ members[msg.user_id].displayname || msg.user_id }} + {{ {"join": "joined", "leave": "left", "invite": "invited"}[msg.content.membership] }} + {{ msg.content.target_id || '' }} +
-- cgit 1.4.1 From 019f3a66f605222576d4a061df1ecfbaebebf0c0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 01:32:17 +0100 Subject: add fixme pointing out name disambiguation is a bit flakey --- webclient/app-filter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/app-filter.js b/webclient/app-filter.js index f007b4c89c..b8f4ed25bc 100644 --- a/webclient/app-filter.js +++ b/webclient/app-filter.js @@ -54,12 +54,15 @@ angular.module('matrixWebClient') }); // FIXME: we shouldn't disambiguate displayNames on every orderMembersList - // invocation but keep track of duplicates incrementally somewhere + // invocation but keep track of duplicates incrementally somewhere angular.forEach(displayNames, function(value, key) { if (value.length > 1) { // console.log(key + ": " + value); for (var i=0; i < value.length; i++) { var v = value[i]; + // FIXME: this permenantly rewrites the displayname for a given + // room member. which means we can't reset their name if it is + // no longer ambiguous! members[v].displayname += " (" + v + ")"; // console.log(v + " " + members[v]); }; -- cgit 1.4.1 From ab27b49deddbd6f74bad126b9a275b015a7fb6cd Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 01:33:05 +0100 Subject: rename autoComplete directive as tabComplete to avoid confusion with the autocomplete html attribute --- webclient/room/room-directive.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'webclient') diff --git a/webclient/room/room-directive.js b/webclient/room/room-directive.js index 94655336df..1a99a37abb 100644 --- a/webclient/room/room-directive.js +++ b/webclient/room/room-directive.js @@ -17,30 +17,30 @@ 'use strict'; angular.module('RoomController') -.directive('autoComplete', ['$timeout', function ($timeout) { +.directive('tabComplete', ['$timeout', function ($timeout) { return function (scope, element, attrs) { element.bind("keydown keypress", function (event) { // console.log("event: " + event.which); if (event.which === 9) { - if (!scope.autoCompleting) { // cache our starting text + if (!scope.tabCompleting) { // cache our starting text // console.log("caching " + element[0].value); - scope.autoCompleteOriginal = element[0].value; - scope.autoCompleting = true; + scope.tabCompleteOriginal = element[0].value; + scope.tabCompleting = true; } if (event.shiftKey) { - scope.autoCompleteIndex--; - if (scope.autoCompleteIndex < 0) { - scope.autoCompleteIndex = 0; + scope.tabCompleteIndex--; + if (scope.tabCompleteIndex < 0) { + scope.tabCompleteIndex = 0; } } else { - scope.autoCompleteIndex++; + scope.tabCompleteIndex++; } var searchIndex = 0; - var targetIndex = scope.autoCompleteIndex; - var text = scope.autoCompleteOriginal; + var targetIndex = scope.tabCompleteIndex; + var text = scope.tabCompleteOriginal; // console.log("targetIndex: " + targetIndex + ", text=" + text); @@ -90,17 +90,17 @@ angular.module('RoomController') element[0].className = ""; }, 150); element[0].value = text; - scope.autoCompleteIndex = 0; + scope.tabCompleteIndex = 0; } } else { - scope.autoCompleteIndex = 0; + scope.tabCompleteIndex = 0; } event.preventDefault(); } - else if (event.which !== 16 && scope.autoCompleting) { - scope.autoCompleting = false; - scope.autoCompleteIndex = 0; + else if (event.which !== 16 && scope.tabCompleting) { + scope.tabCompleting = false; + scope.tabCompleteIndex = 0; } }); }; -- cgit 1.4.1 From fd47f55e943dc6950a1a84414e0ed8a08fbc504c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 01:33:34 +0100 Subject: sacrifice a goat or two to make wordwrap actually work properly --- webclient/app.css | 45 +++++++++++++++++++-------------------------- webclient/room/room.html | 4 ++-- 2 files changed, 21 insertions(+), 28 deletions(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index a63b5db4d6..dfc919e4c0 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -145,6 +145,7 @@ h1 { max-width: 1280px; width: 100%; border-collapse: collapse; + table-layout: fixed; } #messageTable td { @@ -190,25 +191,13 @@ h1 { object-fit: cover; } -.text { - background-color: #eee; - border: 1px solid #d8d8d8; - height: 31px; - display: inline-table; - margin-top: -1px; - max-width: 90%; - font-size: 16px; - /* word-wrap: break-word; */ - word-break: break-all; -} - .emote { - background-color: #fff ! important; + background-color: transparent ! important; border: 0px ! important; } .membership { - background-color: #fff ! important; + background-color: transparent ! important; border: 0px ! important; } @@ -221,6 +210,13 @@ h1 { } .bubble { + background-color: #eee; + border: 1px solid #d8d8d8; + display: inline-block; + margin-bottom: -1px; + max-width: 90%; + font-size: 16px; + word-wrap: break-word; padding-top: 7px; padding-bottom: 5px; padding-left: 1em; @@ -229,27 +225,24 @@ h1 { } .differentUser td { - padding-top: 5px ! important; - margin-top: 5px ! important; + padding-bottom: 5px ! important; } .mine { text-align: right; } -.mine .text { - background-color: #f8f8ff ! important; -} - -.mine .emote { - background-color: #fff ! important; -} - -.mine .membership { - background-color: #fff ! important; +.text.emote .bubble, +.text.membership .bubble, +.mine .text.emote .bubble, +.mine .text.membership .bubble + { + background-color: transparent ! important; + border: 0px ! important; } .mine .text .bubble { + background-color: #f8f8ff ! important; text-align: left ! important; } diff --git a/webclient/room/room.html b/webclient/room/room.html index 4a07dfdaaf..e7560a5dc4 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -29,7 +29,7 @@ + ng-class="(events.rooms[room_id].messages[$index + 1].user_id !== msg.user_id ? 'differentUser' : '') + (msg.user_id === state.user_id ? ' mine' : '')" scroll-item> -- cgit 1.4.1 From aaf623fa534d2486eeadb79de0905c374e019098 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 17:11:39 +0200 Subject: Move profile parts of the rooms page and the config content into a new page: settings --- webclient/app-controller.js | 24 +---- webclient/app.css | 12 --- webclient/app.js | 5 + webclient/index.html | 12 +-- webclient/rooms/rooms-controller.js | 118 +----------------------- webclient/rooms/rooms.html | 48 +--------- webclient/settings/settings-controller.js | 146 ++++++++++++++++++++++++++++++ webclient/settings/settings.html | 73 +++++++++++++++ 8 files changed, 237 insertions(+), 201 deletions(-) create mode 100644 webclient/settings/settings-controller.js create mode 100644 webclient/settings/settings.html (limited to 'webclient') diff --git a/webclient/app-controller.js b/webclient/app-controller.js index 92ad01e4f9..84cb94dc74 100644 --- a/webclient/app-controller.js +++ b/webclient/app-controller.js @@ -31,31 +31,15 @@ angular.module('MatrixWebClientController', ['matrixService']) $rootScope.$on('$routeChangeSuccess', function (event, current, previous) { $scope.location = $location.path(); }); - - - // Manage the display of the current config - $scope.config; - - // Toggles the config display - $scope.showConfig = function() { - if ($scope.config) { - $scope.config = undefined; - } - else { - $scope.config = matrixService.config(); - } - }; - - $scope.closeConfig = function() { - if ($scope.config) { - $scope.config = undefined; - } - }; if (matrixService.isUserLoggedIn()) { // eventStreamService.resume(); } + $scope.go = function(url) { + $location.url(url); + }; + // Logs the user out $scope.logout = function() { // kill the event stream diff --git a/webclient/app.css b/webclient/app.css index 207f35f5f3..72b38cd950 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -308,18 +308,6 @@ h1 { float: right; } -#config { - position: absolute; - z-index: 100; - top: 100px; - left: 50%; - width: 500px; - margin-left: -250px; - text-align: center; - padding: 20px; - background-color: #aaa; -} - .text_entry_section { position: fixed; bottom: 0; diff --git a/webclient/app.js b/webclient/app.js index 944b8ec270..f666a63bf8 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -20,6 +20,7 @@ var matrixWebClient = angular.module('matrixWebClient', [ 'LoginController', 'RoomController', 'RoomsController', + 'SettingsController', 'UserController', 'matrixService', 'eventStreamService', @@ -48,6 +49,10 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', templateUrl: 'rooms/rooms.html', controller: 'RoomsController' }). + when('/settings', { + templateUrl: 'settings/settings.html', + controller: 'SettingsController' + }). when('/user/:user_matrix_id', { templateUrl: 'user/user.html', controller: 'UserController' diff --git a/webclient/index.html b/webclient/index.html index 27d9208193..95f682580e 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -19,6 +19,7 @@ + @@ -33,22 +34,13 @@ -
-
Home server: {{ config.homeserver }}
-
User ID: {{ config.user_id }}
-
Access token: {{ config.access_token }}
-
-
-
- -
diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index 557fbe2378..d891558be5 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -19,7 +19,8 @@ limitations under the License. angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) .controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { - + + $scope.config = matrixService.config(); $scope.rooms = {}; $scope.public_rooms = []; $scope.newRoomId = ""; @@ -37,20 +38,6 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', $scope.joinAlias = { room_alias: "", }; - - $scope.newProfileInfo = { - name: matrixService.config().displayName, - avatar: matrixService.config().avatarUrl, - avatarFile: undefined - }; - - $scope.linkedEmails = { - linkNewEmail: "", // the email entry box - emailBeingAuthed: undefined, // to populate verification text - authTokenId: undefined, // the token id from the IS - emailCode: "", // the code entry box - linkedEmailList: matrixService.config().emailList // linked email list - }; $scope.$on(eventHandlerService.MEMBER_EVENT, function(ngEvent, event, isLive) { var config = matrixService.config(); @@ -170,107 +157,6 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', } ); }; - - $scope.setDisplayName = function(newName) { - matrixService.setDisplayName(newName).then( - function(response) { - $scope.feedback = "Updated display name."; - var config = matrixService.config(); - config.displayName = newName; - matrixService.setConfig(config); - matrixService.saveConfig(); - }, - function(error) { - $scope.feedback = "Can't update display name: " + error.data; - } - ); - }; - - - $scope.$watch("newProfileInfo.avatarFile", function(newValue, oldValue) { - if ($scope.newProfileInfo.avatarFile) { - console.log("Uploading new avatar file..."); - mFileUpload.uploadFile($scope.newProfileInfo.avatarFile).then( - function(url) { - $scope.newProfileInfo.avatar = url; - $scope.setAvatar($scope.newProfileInfo.avatar); - }, - function(error) { - $scope.feedback = "Can't upload image"; - } - ); - } - }); - - $scope.setAvatar = function(newUrl) { - console.log("Updating avatar to "+newUrl); - matrixService.setProfilePictureUrl(newUrl).then( - function(response) { - console.log("Updated avatar"); - $scope.feedback = "Updated avatar."; - var config = matrixService.config(); - config.avatarUrl = newUrl; - matrixService.setConfig(config); - matrixService.saveConfig(); - }, - function(error) { - $scope.feedback = "Can't update avatar: " + error.data; - } - ); - }; - - $scope.linkEmail = function(email) { - matrixService.linkEmail(email).then( - function(response) { - if (response.data.success === true) { - $scope.linkedEmails.authTokenId = response.data.tokenId; - $scope.emailFeedback = "You have been sent an email."; - $scope.linkedEmails.emailBeingAuthed = email; - } - else { - $scope.emailFeedback = "Failed to send email."; - } - }, - function(error) { - $scope.emailFeedback = "Can't send email: " + error.data; - } - ); - }; - - $scope.submitEmailCode = function(code) { - var tokenId = $scope.linkedEmails.authTokenId; - if (tokenId === undefined) { - $scope.emailFeedback = "You have not requested a code with this email."; - return; - } - matrixService.authEmail(matrixService.config().user_id, tokenId, code).then( - function(response) { - if ("success" in response.data && response.data.success === false) { - $scope.emailFeedback = "Failed to authenticate email."; - return; - } - var config = matrixService.config(); - var emailList = {}; - if ("emailList" in config) { - emailList = config.emailList; - } - emailList[response.address] = response; - // save the new email list - config.emailList = emailList; - matrixService.setConfig(config); - matrixService.saveConfig(); - // invalidate the email being authed and update UI. - $scope.linkedEmails.emailBeingAuthed = undefined; - $scope.emailFeedback = ""; - $scope.linkedEmails.linkedEmailList = emailList; - $scope.linkedEmails.linkNewEmail = ""; - $scope.linkedEmails.emailCode = ""; - }, - function(reason) { - $scope.emailFeedback = "Failed to auth email: " + reason; - } - ); - }; $scope.refresh(); }]); diff --git a/webclient/rooms/rooms.html b/webclient/rooms/rooms.html index ba3b7d8bad..2e25c0f084 100644 --- a/webclient/rooms/rooms.html +++ b/webclient/rooms/rooms.html @@ -2,64 +2,26 @@
- +
{{ members[msg.user_id].displayname || msg.user_id }}
{{ (msg.content.hsob_ts || msg.ts) | date:'MMM d HH:mm:ss' }}
@@ -77,7 +77,7 @@ {{ state.user_id }}
- + -- cgit 1.4.1 From 868fa1a1e349d365a41b9594a6fad64fbac36777 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 01:41:38 +0100 Subject: fix weird fontsizes on iOS --- webclient/app.css | 1 + 1 file changed, 1 insertion(+) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index dfc919e4c0..da1a840f4b 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -222,6 +222,7 @@ h1 { padding-left: 1em; padding-right: 1em; vertical-align: middle; + -webkit-text-size-adjust:100% } .differentUser td { -- cgit 1.4.1 From 3248aed03b03e0eba3a4b43776ef2f7685b27701 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 01:54:37 +0100 Subject: fix mainInput retaining focus between sending consecutive messages by disabling commit 955662d6 --- webclient/room/room-controller.js | 4 ++-- webclient/room/room.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'webclient') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 214166a434..451c6242f6 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -33,6 +33,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) can_paginate: true, // this is toggled off when we run out of items paginating: false, // used to avoid concurrent pagination requests pulling in dup contents stream_failure: undefined, // the response when the stream fails + // FIXME: sending has been disabled, as surely messages should be sent in the background rather than locking the UI synchronously --Matthew sending: false // true when a message is being sent. It helps to disable the UI when a process is running }; $scope.members = {}; @@ -239,7 +240,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) } $scope.state.sending = true; - + // Send the text message var promise; // FIXME: handle other commands too @@ -263,7 +264,6 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) }; $scope.onInit = function() { - // $timeout(function() { document.getElementById('textInput').focus() }, 0); console.log("onInit"); // Does the room ID provided in the URL? diff --git a/webclient/room/room.html b/webclient/room/room.html index e7560a5dc4..95da067714 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -77,10 +77,10 @@ {{ state.user_id }} - + - + -- cgit 1.4.1 From 8f7fbc1bb0d9ace628cdf4fa824e96b5d4d30c13 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Fri, 22 Aug 2014 02:11:33 +0100 Subject: improve leftBlock css --- webclient/app.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index da1a840f4b..207f35f5f3 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -153,7 +153,8 @@ h1 { } .leftBlock { - width: 10em; + width: 14em; + word-wrap: break-word; vertical-align: top; background-color: #fff; color: #888; @@ -209,6 +210,10 @@ h1 { height: auto; } +.text { + vertical-align: top; +} + .bubble { background-color: #eee; border: 1px solid #d8d8d8; -- cgit 1.4.1 From c8d0c4762da432aafa4372928aa70ef55646134b Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 10:15:15 +0200 Subject: Safari needs the img.onload event before actually working on the img --- .../components/fileUpload/file-upload-service.js | 1 + .../components/utilities/utilities-service.js | 65 +++++++++++++--------- 2 files changed, 39 insertions(+), 27 deletions(-) (limited to 'webclient') diff --git a/webclient/components/fileUpload/file-upload-service.js b/webclient/components/fileUpload/file-upload-service.js index 6606f31e22..398124fcc4 100644 --- a/webclient/components/fileUpload/file-upload-service.js +++ b/webclient/components/fileUpload/file-upload-service.js @@ -82,6 +82,7 @@ angular.module('mFileUpload', ['matrixService', 'mUtilities']) // First, get the image size mUtilities.getImageSize(imageFile).then( function(size) { + console.log("image size: " + JSON.stringify(size)); // The final operation: send imageFile var uploadImage = function() { diff --git a/webclient/components/utilities/utilities-service.js b/webclient/components/utilities/utilities-service.js index 9cf858ef39..5e9f707221 100644 --- a/webclient/components/utilities/utilities-service.js +++ b/webclient/components/utilities/utilities-service.js @@ -38,10 +38,15 @@ angular.module('mUtilities', []) img.src = e.target.result; // Once ready, returns its size - deferred.resolve({ - width: img.width, - height: img.height - }); + img.onload = function() { + deferred.resolve({ + width: img.width, + height: img.height + }); + }; + img.onerror = function(e) { + deferred.reject(e); + }; }; reader.onerror = function(e) { deferred.reject(e); @@ -71,33 +76,39 @@ angular.module('mUtilities', []) reader.onload = function(e) { img.src = e.target.result; + + // Once ready, returns its size + img.onload = function() { + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); - var ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0); - - var MAX_WIDTH = maxSize; - var MAX_HEIGHT = maxSize; - var width = img.width; - var height = img.height; + var MAX_WIDTH = maxSize; + var MAX_HEIGHT = maxSize; + var width = img.width; + var height = img.height; - if (width > height) { - if (width > MAX_WIDTH) { - height *= MAX_WIDTH / width; - width = MAX_WIDTH; - } - } else { - if (height > MAX_HEIGHT) { - width *= MAX_HEIGHT / height; - height = MAX_HEIGHT; + if (width > height) { + if (width > MAX_WIDTH) { + height *= MAX_WIDTH / width; + width = MAX_WIDTH; + } + } else { + if (height > MAX_HEIGHT) { + width *= MAX_HEIGHT / height; + height = MAX_HEIGHT; + } } - } - canvas.width = width; - canvas.height = height; - var ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0, width, height); + canvas.width = width; + canvas.height = height; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, width, height); - var dataUrl = canvas.toDataURL("image/jpeg", 0.7); - deferred.resolve(self.dataURItoBlob(dataUrl)); + var dataUrl = canvas.toDataURL("image/jpeg", 0.7); + deferred.resolve(self.dataURItoBlob(dataUrl)); + }; + img.onerror = function(e) { + deferred.reject(e); + }; }; reader.onerror = function(e) { deferred.reject(e); -- cgit 1.4.1 From 53f4fbd99a223a4321377ea670d1d19b669b6f4a Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 10:48:00 +0200 Subject: resizeImage: generate an image in the format of the original image. (Tested with tranparent PNG, transparent GIF, BMP, JPEG) --- webclient/components/utilities/utilities-service.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/components/utilities/utilities-service.js b/webclient/components/utilities/utilities-service.js index 5e9f707221..3df2f04458 100644 --- a/webclient/components/utilities/utilities-service.js +++ b/webclient/components/utilities/utilities-service.js @@ -103,7 +103,9 @@ angular.module('mUtilities', []) var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); - var dataUrl = canvas.toDataURL("image/jpeg", 0.7); + // Extract image data in the same format as the original one. + // The 0.7 compression value will work with formats that supports it like JPEG. + var dataUrl = canvas.toDataURL(imageFile.type, 0.7); deferred.resolve(self.dataURItoBlob(dataUrl)); }; img.onerror = function(e) { -- cgit 1.4.1 From acf51276042cf438cbb02bb5ef31c42206d7685d Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 22 Aug 2014 10:25:27 +0100 Subject: Make the content repo work with in daemon mode. Return the full url on upload. Update the webclient to use new content repo api. --- synapse/app/homeserver.py | 5 +++-- synapse/http/server.py | 26 +++++++++++++++++----- .../components/fileUpload/file-upload-service.js | 2 +- 3 files changed, 24 insertions(+), 9 deletions(-) (limited to 'webclient') diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 6b39da4a7d..495149466c 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -56,7 +56,7 @@ class SynapseHomeServer(HomeServer): return File("webclient") # TODO configurable? def build_resource_for_content_repo(self): - return ContentRepoResource("uploads", self.auth) + return ContentRepoResource(self, self.upload_dir, self.auth) def build_db_pool(self): """ Set up all the dbs. Since all the *.sql have IF NOT EXISTS, so we @@ -257,7 +257,8 @@ def setup(): hs = SynapseHomeServer( args.host, - db_name=db_name + upload_dir=os.path.abspath("uploads"), + db_name=db_name, ) # This object doesn't need to be saved because it's set as the handler for diff --git a/synapse/http/server.py b/synapse/http/server.py index c28d9a33f9..d1f99460c1 100644 --- a/synapse/http/server.py +++ b/synapse/http/server.py @@ -212,8 +212,9 @@ class ContentRepoResource(resource.Resource): """ isLeaf = True - def __init__(self, directory, auth): + def __init__(self, hs, directory, auth): resource.Resource.__init__(self) + self.hs = hs self.directory = directory self.auth = auth @@ -250,7 +251,8 @@ class ContentRepoResource(resource.Resource): file_ext = re.sub("[^a-z]", "", file_ext) suffix += "." + file_ext - file_path = os.path.join(self.directory, prefix + main_part + suffix) + file_name = prefix + main_part + suffix + file_path = os.path.join(self.directory, file_name) logger.info("User %s is uploading a file to path %s", auth_user.to_string(), file_path) @@ -259,8 +261,8 @@ class ContentRepoResource(resource.Resource): attempts = 0 while os.path.exists(file_path): main_part = random_string(24) - file_path = os.path.join(self.directory, - prefix + main_part + suffix) + file_name = prefix + main_part + suffix + file_path = os.path.join(self.directory, file_name) attempts += 1 if attempts > 25: # really? Really? raise SynapseError(500, "Unable to create file.") @@ -272,11 +274,14 @@ class ContentRepoResource(resource.Resource): # servers. # TODO: A little crude here, we could do this better. - filename = request.path.split(self.directory + "/")[1] + filename = request.path.split('/')[-1] # be paranoid filename = re.sub("[^0-9A-z.-_]", "", filename) file_path = self.directory + "/" + filename + + logger.debug("Searching for %s", file_path) + if os.path.isfile(file_path): # filename has the content type base64_contentype = filename.split(".")[1] @@ -304,6 +309,10 @@ class ContentRepoResource(resource.Resource): self._async_render(request) return server.NOT_DONE_YET + def render_OPTIONS(self, request): + respond_with_json_bytes(request, 200, {}, send_cors=True) + return server.NOT_DONE_YET + @defer.inlineCallbacks def _async_render(self, request): try: @@ -313,8 +322,13 @@ class ContentRepoResource(resource.Resource): with open(fname, "wb") as f: f.write(request.content.read()) + + # FIXME (erikj): These should use constants. + file_name = os.path.basename(fname) + url = "http://%s/matrix/content/%s" % (self.hs.hostname, file_name) + respond_with_json_bytes(request, 200, - json.dumps({"content_token": fname}), + json.dumps({"content_token": url}), send_cors=True) except CodeMessageException as e: diff --git a/webclient/components/fileUpload/file-upload-service.js b/webclient/components/fileUpload/file-upload-service.js index 398124fcc4..5f01478fd1 100644 --- a/webclient/components/fileUpload/file-upload-service.js +++ b/webclient/components/fileUpload/file-upload-service.js @@ -33,7 +33,7 @@ angular.module('mFileUpload', ['matrixService', 'mUtilities']) 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; + var content_url = response.data.content_token; console.log(" -> Successfully uploaded! Available at " + content_url); deferred.resolve(content_url); }, -- cgit 1.4.1 From 3c349b408b302b21bf2ad0d9086fc3b6fb46dc7a Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 22 Aug 2014 11:34:27 +0200 Subject: Update web client to use new IS API. --- webclient/components/matrix/matrix-service.js | 18 +++++--- webclient/login/login-controller.js | 2 + webclient/rooms/rooms-controller.js | 62 +++++++++++++++++++-------- 3 files changed, 58 insertions(+), 24 deletions(-) (limited to 'webclient') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index fa5a6091d3..d5738e01c8 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -79,7 +79,6 @@ angular.module('matrixService', []) return $http(request); }; - return { /****** Home server API ******/ prefix: prefixPath, @@ -310,17 +309,25 @@ angular.module('matrixService', []) }, // hit the Identity Server for a 3PID request. - linkEmail: function(email) { + linkEmail: function(email, clientSecret, sendAttempt) { var path = "/matrix/identity/api/v1/validate/email/requestToken" - var data = "clientSecret=abc123&email=" + encodeURIComponent(email); + var data = "clientSecret="+clientSecret+"&email=" + encodeURIComponent(email)+"&sendAttempt="+sendAttempt; var headers = {}; headers["Content-Type"] = "application/x-www-form-urlencoded"; return doBaseRequest(config.identityServer, "POST", path, {}, data, headers); }, - authEmail: function(userId, tokenId, code) { + authEmail: function(clientSecret, tokenId, code) { var path = "/matrix/identity/api/v1/validate/email/submitToken"; - var data = "token="+code+"&mxId="+encodeURIComponent(userId)+"&tokenId="+tokenId; + var data = "token="+code+"&sid="+tokenId+"&clientSecret="+clientSecret; + var headers = {}; + headers["Content-Type"] = "application/x-www-form-urlencoded"; + return doBaseRequest(config.identityServer, "POST", path, {}, data, headers); + }, + + bindEmail: function(userId, tokenId, clientSecret) { + var path = "/matrix/identity/api/v1/3pid/bind"; + var data = "mxid="+encodeURIComponent(userId)+"&sid="+tokenId+"&clientSecret="+clientSecret; var headers = {}; headers["Content-Type"] = "application/x-www-form-urlencoded"; return doBaseRequest(config.identityServer, "POST", path, {}, data, headers); @@ -393,6 +400,7 @@ angular.module('matrixService', []) // Set a new config (Use saveConfig to actually store it permanently) setConfig: function(newConfig) { config = newConfig; + console.log("new IS: "+config.identityServer); }, // Commits config into permanent storage diff --git a/webclient/login/login-controller.js b/webclient/login/login-controller.js index 67d0b7b90c..35886c5583 100644 --- a/webclient/login/login-controller.js +++ b/webclient/login/login-controller.js @@ -70,6 +70,7 @@ angular.module('LoginController', ['matrixService']) $scope.login = function() { matrixService.setConfig({ homeserver: $scope.account.homeserver, + identityServer: $scope.account.identityServer, user_id: $scope.account.user_id }); // try to login @@ -79,6 +80,7 @@ angular.module('LoginController', ['matrixService']) $scope.feedback = "Login successful."; matrixService.setConfig({ homeserver: $scope.account.homeserver, + identityServer: $scope.account.identityServer, user_id: response.data.user_id, access_token: response.data.access_token }); diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index c25e24c8bc..65d345d7a6 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -48,6 +48,8 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', linkNewEmail: "", // the email entry box emailBeingAuthed: undefined, // to populate verification text authTokenId: undefined, // the token id from the IS + clientSecret: undefined, // our client secret + sendAttempt: 1, emailCode: "", // the code entry box linkedEmailList: matrixService.config().emailList // linked email list }; @@ -207,11 +209,27 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', ); }; + var generateClientSecret = function() { + var ret = ""; + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + for (var i = 0; i < 32; i++) { + ret += chars.charAt(Math.floor(Math.random() * chars.length)); + } + + return ret; + }; + + $scope.linkEmail = function(email) { - matrixService.linkEmail(email).then( + if (email != $scope.linkedEmails.emailBeingAuthed) { + $scope.linkedEmails.clientSecret = generateClientSecret(); + $scope.linkedEmails.sendAttempt = 1; + } + matrixService.linkEmail(email, $scope.linkedEmails.clientSecret, $scope.linkedEmails.sendAttempt).then( function(response) { if (response.data.success === true) { - $scope.linkedEmails.authTokenId = response.data.tokenId; + $scope.linkedEmails.authTokenId = response.data.sid; $scope.emailFeedback = "You have been sent an email."; $scope.linkedEmails.emailBeingAuthed = email; } @@ -231,28 +249,34 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', $scope.emailFeedback = "You have not requested a code with this email."; return; } - matrixService.authEmail(matrixService.config().user_id, tokenId, code).then( + matrixService.authEmail(matrixService.config().user_id, tokenId, code, $scope.linkedEmails.clientSecret).then( function(response) { if ("success" in response.data && response.data.success === false) { $scope.emailFeedback = "Failed to authenticate email."; return; } - var config = matrixService.config(); - var emailList = {}; - if ("emailList" in config) { - emailList = config.emailList; - } - emailList[response.address] = response; - // save the new email list - config.emailList = emailList; - matrixService.setConfig(config); - matrixService.saveConfig(); - // invalidate the email being authed and update UI. - $scope.linkedEmails.emailBeingAuthed = undefined; - $scope.emailFeedback = ""; - $scope.linkedEmails.linkedEmailList = emailList; - $scope.linkedEmails.linkNewEmail = ""; - $scope.linkedEmails.emailCode = ""; + matrixService.bindEmail(matrixService.config().user_id, tokenId, $scope.linkedEmails.clientSecret).then( + function(response) { + var config = matrixService.config(); + var emailList = {}; + if ("emailList" in config) { + emailList = config.emailList; + } + emailList[$scope.linkedEmails.emailBeingAuthed] = response; + // save the new email list + config.emailList = emailList; + matrixService.setConfig(config); + matrixService.saveConfig(); + // invalidate the email being authed and update UI. + $scope.linkedEmails.emailBeingAuthed = undefined; + $scope.emailFeedback = ""; + $scope.linkedEmails.linkedEmailList = emailList; + $scope.linkedEmails.linkNewEmail = ""; + $scope.linkedEmails.emailCode = ""; + }, function(reason) { + $scope.emailFeedback = "Failed to link email: " + reason; + } + ); }, function(reason) { $scope.emailFeedback = "Failed to auth email: " + reason; -- cgit 1.4.1 From dde50d4245136cdbd11ac3b4af42102945cd14f9 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 11:43:54 +0200 Subject: Use $location.url instead of $location.path to get clean page URL without hash arguments of the previous page. This happpens with room URL like http://127.0.0.1:8080/matrix/client/#/room/#public:localhost. The second hash part is transferred to the next page when using $location.path. --- webclient/app-controller.js | 2 +- webclient/login/login-controller.js | 4 ++-- webclient/room/room-controller.js | 6 +++--- webclient/rooms/rooms-controller.js | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'webclient') diff --git a/webclient/app-controller.js b/webclient/app-controller.js index c53f29aa77..92ad01e4f9 100644 --- a/webclient/app-controller.js +++ b/webclient/app-controller.js @@ -66,7 +66,7 @@ angular.module('MatrixWebClientController', ['matrixService']) matrixService.saveConfig(); // And go to the login page - $location.path("login"); + $location.url("login"); }; // Listen to the event indicating that the access token is no longer valid. diff --git a/webclient/login/login-controller.js b/webclient/login/login-controller.js index 67d0b7b90c..2f1f224a94 100644 --- a/webclient/login/login-controller.js +++ b/webclient/login/login-controller.js @@ -53,7 +53,7 @@ angular.module('LoginController', ['matrixService']) matrixService.saveConfig(); eventStreamService.resume(); // Go to the user's rooms list page - $location.path("rooms"); + $location.url("rooms"); }, function(error) { if (error.data) { @@ -84,7 +84,7 @@ angular.module('LoginController', ['matrixService']) }); matrixService.saveConfig(); eventStreamService.resume(); - $location.path("rooms"); + $location.url("rooms"); } else { $scope.feedback = "Failed to login: " + JSON.stringify(response.data); diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 451c6242f6..26d1836fc2 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -293,7 +293,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) else { // In case of issue, go to the default page console.log("Error: cannot extract room alias"); - $location.path("/"); + $location.url("/"); return; } } @@ -310,7 +310,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) function () { // In case of issue, go to the default page console.log("Error: cannot resolve room alias"); - $location.path("/"); + $location.url("/"); }); } }; @@ -364,7 +364,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) matrixService.leave($scope.room_id).then( function(response) { console.log("Left room "); - $location.path("rooms"); + $location.url("rooms"); }, function(error) { $scope.feedback = "Failed to leave room: " + error.data.error; diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js index c2d7bcb6f3..557fbe2378 100644 --- a/webclient/rooms/rooms-controller.js +++ b/webclient/rooms/rooms-controller.js @@ -141,17 +141,17 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', // Go to a room $scope.goToRoom = function(room_id) { // Simply open the room page on this room id - //$location.path("room/" + room_id); + //$location.url("room/" + room_id); matrixService.join(room_id).then( function(response) { if (response.data.hasOwnProperty("room_id")) { if (response.data.room_id != room_id) { - $location.path("room/" + response.data.room_id); + $location.url("room/" + response.data.room_id); return; } } - $location.path("room/" + room_id); + $location.url("room/" + room_id); }, function(error) { $scope.feedback = "Can't join room: " + error.data; @@ -163,7 +163,7 @@ angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', matrixService.joinAlias(room_alias).then( function(response) { // Go to this room - $location.path("room/" + room_alias); + $location.url("room/" + room_alias); }, function(error) { $scope.feedback = "Can't join room: " + error.data; -- cgit 1.4.1 From 74c90f78159e8067b25bfa8a009d2e68419947c8 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 22 Aug 2014 10:50:10 +0100 Subject: Reinitialize room when creating a RoomController so that we start off with a clean slate, as it expects/ --- webclient/components/matrix/event-handler-service.js | 12 +++++++++++- webclient/room/room-controller.js | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index 6a01b3fb55..aa8867425e 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -44,6 +44,12 @@ angular.module('eventHandlerService', []) $rootScope.events.rooms[room_id].members = {}; } } + + var reInitRoom = function(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) { @@ -118,6 +124,10 @@ angular.module('eventHandlerService', []) for (var i=0; i Date: Fri, 22 Aug 2014 10:50:38 +0100 Subject: Keep track of people's presence and query that when we update the members list. --- webclient/components/matrix/event-handler-service.js | 3 +++ webclient/room/room-controller.js | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'webclient') diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index aa8867425e..b5eb73d92b 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -35,6 +35,8 @@ angular.module('eventHandlerService', []) $rootScope.events = { rooms: {}, // will contain roomId: { messages:[], members:{userid1: event} } }; + + $rootScope.presence = {}; var initRoom = function(room_id) { if (!(room_id in $rootScope.events.rooms)) { @@ -91,6 +93,7 @@ angular.module('eventHandlerService', []) }; var handlePresence = function(event, isLiveEvent) { + $rootScope.presence[event.content.user_id] = event; $rootScope.$broadcast(PRESENCE_EVENT, event, isLiveEvent); }; diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index a0485e84e8..e204a27e04 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -15,8 +15,8 @@ limitations under the License. */ angular.module('RoomController', ['ngSanitize', 'mUtilities']) -.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService', 'mFileUpload', 'mUtilities', - function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService, mFileUpload, mUtilities) { +.controller('RoomController', ['$scope', '$http', '$timeout', '$routeParams', '$location', 'matrixService', 'eventStreamService', 'eventHandlerService', 'mFileUpload', 'mUtilities', '$rootScope', + function($scope, $http, $timeout, $routeParams, $location, matrixService, eventStreamService, eventHandlerService, mFileUpload, mUtilities, $rootScope) { 'use strict'; var MESSAGES_PER_PAGINATION = 30; var THUMBNAIL_SIZE = 320; @@ -199,6 +199,10 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) ); }); */ + + if (chunk.target_user_id in $rootScope.presence) { + updatePresence($rootScope.presence[chunk.target_user_id]); + } } else { // selectively update membership else it will nuke the picture and displayname too :/ @@ -265,7 +269,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) $scope.onInit = function() { console.log("onInit"); - + // Does the room ID provided in the URL? var room_id_or_alias; if ($routeParams.room_id_or_alias) { -- cgit 1.4.1 From f3cea238b9c51861965d31cd9352153338d6705b Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 22 Aug 2014 10:56:09 +0100 Subject: Check if the membership message was for the room we were in before updating the membership list --- webclient/room/room-controller.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'webclient') diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index e204a27e04..58ba432ce5 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -152,6 +152,8 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) }; var updateMemberList = function(chunk) { + if (chunk.room_id != $scope.room_id) return; + var isNewMember = !(chunk.target_user_id in $scope.members); if (isNewMember) { // FIXME: why are we copying these fields around inside chunk? -- cgit 1.4.1 From f40844def237f514e2a7398e8c7ed65b45277b0d Mon Sep 17 00:00:00 2001 From: root Date: Fri, 22 Aug 2014 16:20:53 +0100 Subject: avatar url --- webclient/rooms/rooms.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/rooms/rooms.html b/webclient/rooms/rooms.html index ba3b7d8bad..5e422bf83b 100644 --- a/webclient/rooms/rooms.html +++ b/webclient/rooms/rooms.html @@ -19,7 +19,7 @@ -->
- +
- +
- -
- - +
+
{{ config.displayName }}
+
{{ config.user_id }}
- -
-
- - -
-
- -
- -
-
- - - {{ emailFeedback }} -
-
- Enter validation token for {{ linkedEmails.emailBeingAuthed }}: -
- - -
- Linked emails: - - - - -
{{address}}
-
-

My rooms

diff --git a/webclient/settings/settings-controller.js b/webclient/settings/settings-controller.js new file mode 100644 index 0000000000..5d3f7cb2b8 --- /dev/null +++ b/webclient/settings/settings-controller.js @@ -0,0 +1,146 @@ +/* +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('SettingsController', ['matrixService', 'mFileUpload']) +.controller('SettingsController', ['$scope', 'matrixService', 'mFileUpload', + function($scope, matrixService, mFileUpload) { + $scope.config = matrixService.config(); + + $scope.profile = { + displayName: $scope.config.displayName, + avatarUrl: $scope.config.avatarUrl + }; + + $scope.$watch("profile.avatarFile", function(newValue, oldValue) { + if ($scope.profile.avatarFile) { + console.log("Uploading new avatar file..."); + mFileUpload.uploadFile($scope.profile.avatarFile).then( + function(url) { + $scope.profile.avatarUrl = url; + }, + function(error) { + $scope.feedback = "Can't upload image"; + } + ); + } + }); + + $scope.saveProfile = function() { + if ($scope.profile.displayName !== $scope.config.displayName) { + setDisplayName($scope.profile.displayName); + } + if ($scope.profile.avatarUrl !== $scope.config.avatarUrl) { + setAvatar($scope.profile.avatarUrl); + } + }; + + var setDisplayName = function(displayName) { + matrixService.setDisplayName(displayName).then( + function(response) { + $scope.feedback = "Updated display name."; + + var config = matrixService.config(); + config.displayName = displayName; + matrixService.setConfig(config); + matrixService.saveConfig(); + }, + function(error) { + $scope.feedback = "Can't update display name: " + error.data; + } + ); + }; + + var setAvatar = function(avatarURL) { + console.log("Updating avatar to " + avatarURL); + matrixService.setProfilePictureUrl(avatarURL).then( + function(response) { + console.log("Updated avatar"); + $scope.feedback = "Updated avatar."; + + var config = matrixService.config(); + config.avatarUrl = avatarURL; + matrixService.setConfig(config); + matrixService.saveConfig(); + }, + function(error) { + $scope.feedback = "Can't update avatar: " + error.data; + } + ); + }; + + $scope.linkedEmails = { + linkNewEmail: "", // the email entry box + emailBeingAuthed: undefined, // to populate verification text + authTokenId: undefined, // the token id from the IS + emailCode: "", // the code entry box + linkedEmailList: matrixService.config().emailList // linked email list + }; + + $scope.linkEmail = function(email) { + matrixService.linkEmail(email).then( + function(response) { + if (response.data.success === true) { + $scope.linkedEmails.authTokenId = response.data.tokenId; + $scope.emailFeedback = "You have been sent an email."; + $scope.linkedEmails.emailBeingAuthed = email; + } + else { + $scope.emailFeedback = "Failed to send email."; + } + }, + function(error) { + $scope.emailFeedback = "Can't send email: " + error.data; + } + ); + }; + + $scope.submitEmailCode = function(code) { + var tokenId = $scope.linkedEmails.authTokenId; + if (tokenId === undefined) { + $scope.emailFeedback = "You have not requested a code with this email."; + return; + } + matrixService.authEmail(matrixService.config().user_id, tokenId, code).then( + function(response) { + if ("success" in response.data && response.data.success === false) { + $scope.emailFeedback = "Failed to authenticate email."; + return; + } + var config = matrixService.config(); + var emailList = {}; + if ("emailList" in config) { + emailList = config.emailList; + } + emailList[response.address] = response; + // save the new email list + config.emailList = emailList; + matrixService.setConfig(config); + matrixService.saveConfig(); + // invalidate the email being authed and update UI. + $scope.linkedEmails.emailBeingAuthed = undefined; + $scope.emailFeedback = ""; + $scope.linkedEmails.linkedEmailList = emailList; + $scope.linkedEmails.linkNewEmail = ""; + $scope.linkedEmails.emailCode = ""; + }, + function(reason) { + $scope.emailFeedback = "Failed to auth email: " + reason; + } + ); + }; +}]); \ No newline at end of file diff --git a/webclient/settings/settings.html b/webclient/settings/settings.html new file mode 100644 index 0000000000..63b12c8f56 --- /dev/null +++ b/webclient/settings/settings.html @@ -0,0 +1,73 @@ +
+ +
+
+ +

Me

+
+
+ + + + + + +
+
+ +
+
+
+ +
+
+ +
+
+
+
+ +

Linked emails

+
+
+ + + {{ emailFeedback }} +
+
+ Enter validation token for {{ linkedEmails.emailBeingAuthed }}: +
+ + +
+ + + + +
{{address}}
+
+
+ +

Configuration

+
+
Home server: {{ config.homeserver }}
+
User ID: {{ config.user_id }}
+
Access token: {{ config.access_token }}
+
+
+ +
+
+
+
+ + {{ feedback }} + +
+
+
-- cgit 1.4.1 From 61cac4df6e40eb19a874e35e8ed79efc7ec1fb38 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 17:59:48 +0200 Subject: renamed rooms to home --- webclient/home/rooms-controller.js | 162 ++++++++++++++++++++++++++++++++++ webclient/home/rooms.html | 63 +++++++++++++ webclient/nbproject/licenseheader.txt | 16 ++++ webclient/rooms/rooms-controller.js | 162 ---------------------------------- webclient/rooms/rooms.html | 63 ------------- 5 files changed, 241 insertions(+), 225 deletions(-) create mode 100644 webclient/home/rooms-controller.js create mode 100644 webclient/home/rooms.html create mode 100644 webclient/nbproject/licenseheader.txt delete mode 100644 webclient/rooms/rooms-controller.js delete mode 100644 webclient/rooms/rooms.html (limited to 'webclient') diff --git a/webclient/home/rooms-controller.js b/webclient/home/rooms-controller.js new file mode 100644 index 0000000000..d891558be5 --- /dev/null +++ b/webclient/home/rooms-controller.js @@ -0,0 +1,162 @@ +/* +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('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) +.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', + function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { + + $scope.config = matrixService.config(); + $scope.rooms = {}; + $scope.public_rooms = []; + $scope.newRoomId = ""; + $scope.feedback = ""; + + $scope.newRoom = { + room_id: "", + private: false + }; + + $scope.goToRoom = { + room_id: "", + }; + + $scope.joinAlias = { + room_alias: "", + }; + + $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_display_name = event.user_id + "'s room"; + $scope.rooms[event.room_id] = event; + } + }); + + var assignRoomAliases = function(data) { + for (var i=0; i + +
+
+ +
+
+ + + + + +
+
+ +
+
+
+
{{ config.displayName }}
+
{{ config.user_id }}
+
+
+
+
+ +

My rooms

+ +
+
+ {{ room.room_display_name }} {{room.membership === 'invite' ? ' (invited)' : ''}} +
+
+
+ +

Public rooms

+ + +
+ +
+
+ + private + +
+
+
+
+ + +
+
+
+ + {{ feedback }} + +
+
+
diff --git a/webclient/nbproject/licenseheader.txt b/webclient/nbproject/licenseheader.txt new file mode 100644 index 0000000000..36e6dcf181 --- /dev/null +++ b/webclient/nbproject/licenseheader.txt @@ -0,0 +1,16 @@ +/* +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. +*/ + diff --git a/webclient/rooms/rooms-controller.js b/webclient/rooms/rooms-controller.js deleted file mode 100644 index d891558be5..0000000000 --- a/webclient/rooms/rooms-controller.js +++ /dev/null @@ -1,162 +0,0 @@ -/* -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('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) -.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', - function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { - - $scope.config = matrixService.config(); - $scope.rooms = {}; - $scope.public_rooms = []; - $scope.newRoomId = ""; - $scope.feedback = ""; - - $scope.newRoom = { - room_id: "", - private: false - }; - - $scope.goToRoom = { - room_id: "", - }; - - $scope.joinAlias = { - room_alias: "", - }; - - $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_display_name = event.user_id + "'s room"; - $scope.rooms[event.room_id] = event; - } - }); - - var assignRoomAliases = function(data) { - for (var i=0; i - -
-
- -
-
- - - - - -
-
- -
-
-
-
{{ config.displayName }}
-
{{ config.user_id }}
-
-
-
-
- -

My rooms

- -
-
- {{ room.room_display_name }} {{room.membership === 'invite' ? ' (invited)' : ''}} -
-
-
- -

Public rooms

- - -
- -
-
- - private - -
-
-
-
- - -
-
-
- - {{ feedback }} - -
-
- -- cgit 1.4.1 From 4c7df5236098006b62a71e2e06a918a812d5dd3f Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 18:01:08 +0200 Subject: renamed rooms to home - renamed files --- webclient/home/home-controller.js | 162 +++++++++++++++++++++++++ webclient/home/home.html | 63 ++++++++++ webclient/home/rooms-controller.js | 162 ------------------------- webclient/home/rooms.html | 63 ---------- webclient/nbproject/private/private.properties | 1 + webclient/nbproject/private/private.xml | 22 ++++ 6 files changed, 248 insertions(+), 225 deletions(-) create mode 100644 webclient/home/home-controller.js create mode 100644 webclient/home/home.html delete mode 100644 webclient/home/rooms-controller.js delete mode 100644 webclient/home/rooms.html create mode 100644 webclient/nbproject/private/private.properties create mode 100644 webclient/nbproject/private/private.xml (limited to 'webclient') diff --git a/webclient/home/home-controller.js b/webclient/home/home-controller.js new file mode 100644 index 0000000000..d891558be5 --- /dev/null +++ b/webclient/home/home-controller.js @@ -0,0 +1,162 @@ +/* +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('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) +.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', + function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { + + $scope.config = matrixService.config(); + $scope.rooms = {}; + $scope.public_rooms = []; + $scope.newRoomId = ""; + $scope.feedback = ""; + + $scope.newRoom = { + room_id: "", + private: false + }; + + $scope.goToRoom = { + room_id: "", + }; + + $scope.joinAlias = { + room_alias: "", + }; + + $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_display_name = event.user_id + "'s room"; + $scope.rooms[event.room_id] = event; + } + }); + + var assignRoomAliases = function(data) { + for (var i=0; i + +
+
+ +
+
+ + + + + +
+
+ +
+
+
+
{{ config.displayName }}
+
{{ config.user_id }}
+
+
+
+
+ +

My rooms

+ +
+
+ {{ room.room_display_name }} {{room.membership === 'invite' ? ' (invited)' : ''}} +
+
+
+ +

Public rooms

+ + +
+ +
+
+ + private + +
+
+
+
+ + +
+
+
+ + {{ feedback }} + +
+
+ diff --git a/webclient/home/rooms-controller.js b/webclient/home/rooms-controller.js deleted file mode 100644 index d891558be5..0000000000 --- a/webclient/home/rooms-controller.js +++ /dev/null @@ -1,162 +0,0 @@ -/* -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('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) -.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', - function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { - - $scope.config = matrixService.config(); - $scope.rooms = {}; - $scope.public_rooms = []; - $scope.newRoomId = ""; - $scope.feedback = ""; - - $scope.newRoom = { - room_id: "", - private: false - }; - - $scope.goToRoom = { - room_id: "", - }; - - $scope.joinAlias = { - room_alias: "", - }; - - $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_display_name = event.user_id + "'s room"; - $scope.rooms[event.room_id] = event; - } - }); - - var assignRoomAliases = function(data) { - for (var i=0; i - -
-
- -
-
- - - - - -
-
- -
-
-
-
{{ config.displayName }}
-
{{ config.user_id }}
-
-
-
-
- -

My rooms

- -
-
- {{ room.room_display_name }} {{room.membership === 'invite' ? ' (invited)' : ''}} -
-
-
- -

Public rooms

- - -
- -
-
- - private - -
-
-
-
- - -
-
-
- - {{ feedback }} - -
-
- diff --git a/webclient/nbproject/private/private.properties b/webclient/nbproject/private/private.properties new file mode 100644 index 0000000000..3b1a22e6c9 --- /dev/null +++ b/webclient/nbproject/private/private.properties @@ -0,0 +1 @@ +browser=Chrome.INTEGRATED diff --git a/webclient/nbproject/private/private.xml b/webclient/nbproject/private/private.xml new file mode 100644 index 0000000000..75bc70106a --- /dev/null +++ b/webclient/nbproject/private/private.xml @@ -0,0 +1,22 @@ + + + + + + file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/matrix-service.js + file:/Users/manu/UC/matrix/github/synapse/webclient/app.css + file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/event-handler-service.js + file:/Users/manu/UC/matrix/github/synapse/webclient/app-controller.js + file:/Users/manu/UC/matrix/github/synapse/webclient/room/room.html + file:/Users/manu/UC/matrix/github/synapse/webclient/login/login.html + file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/event-stream-service.js + file:/Users/manu/UC/matrix/github/synapse/webclient/components/fileUpload/file-upload-service.js + file:/Users/manu/UC/matrix/github/synapse/webclient/index.html + file:/Users/manu/UC/matrix/github/synapse/webclient/room/room-controller.js + file:/Users/manu/UC/matrix/github/synapse/webclient/rooms/rooms.html + file:/Users/manu/UC/matrix/github/synapse/webclient/app.js + file:/Users/manu/UC/matrix/github/synapse/webclient/rooms/rooms-controller.js + file:/Users/manu/UC/matrix/github/synapse/webclient/components/fileInput/file-input-directive.js + + + -- cgit 1.4.1 From de0706493affc7d8aa6d294fbd531fa0b75ef49c Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 18:08:03 +0200 Subject: Use /home everywhere --- webclient/app.js | 10 +++++----- webclient/home/home-controller.js | 4 ++-- webclient/home/home.html | 2 +- webclient/index.html | 2 +- webclient/login/login-controller.js | 4 ++-- webclient/room/room-controller.js | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'webclient') diff --git a/webclient/app.js b/webclient/app.js index f666a63bf8..e5d8513944 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -19,7 +19,7 @@ var matrixWebClient = angular.module('matrixWebClient', [ 'MatrixWebClientController', 'LoginController', 'RoomController', - 'RoomsController', + 'HomeController', 'SettingsController', 'UserController', 'matrixService', @@ -45,9 +45,9 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', templateUrl: 'room/room.html', controller: 'RoomController' }). - when('/rooms', { - templateUrl: 'rooms/rooms.html', - controller: 'RoomsController' + when('/home', { + templateUrl: 'home/home.html', + controller: 'HomeController' }). when('/settings', { templateUrl: 'settings/settings.html', @@ -58,7 +58,7 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', controller: 'UserController' }). otherwise({ - redirectTo: '/rooms' + redirectTo: '/home' }); $provide.factory('AccessTokenInterceptor', ['$q', '$rootScope', diff --git a/webclient/home/home-controller.js b/webclient/home/home-controller.js index d891558be5..a3d7308312 100644 --- a/webclient/home/home-controller.js +++ b/webclient/home/home-controller.js @@ -16,8 +16,8 @@ limitations under the License. 'use strict'; -angular.module('RoomsController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) -.controller('RoomsController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', +angular.module('HomeController', ['matrixService', 'mFileInput', 'mFileUpload', 'eventHandlerService']) +.controller('HomeController', ['$scope', '$location', 'matrixService', 'mFileUpload', 'eventHandlerService', 'eventStreamService', function($scope, $location, matrixService, mFileUpload, eventHandlerService, eventStreamService) { $scope.config = matrixService.config(); diff --git a/webclient/home/home.html b/webclient/home/home.html index 2e25c0f084..4818d414b6 100644 --- a/webclient/home/home.html +++ b/webclient/home/home.html @@ -1,4 +1,4 @@ -
+
diff --git a/webclient/index.html b/webclient/index.html index 95f682580e..ed1d9bb031 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -15,10 +15,10 @@ + - diff --git a/webclient/login/login-controller.js b/webclient/login/login-controller.js index 2f1f224a94..cd13dcea82 100644 --- a/webclient/login/login-controller.js +++ b/webclient/login/login-controller.js @@ -53,7 +53,7 @@ angular.module('LoginController', ['matrixService']) matrixService.saveConfig(); eventStreamService.resume(); // Go to the user's rooms list page - $location.url("rooms"); + $location.url("home"); }, function(error) { if (error.data) { @@ -84,7 +84,7 @@ angular.module('LoginController', ['matrixService']) }); matrixService.saveConfig(); eventStreamService.resume(); - $location.url("rooms"); + $location.url("home"); } else { $scope.feedback = "Failed to login: " + JSON.stringify(response.data); diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 26d1836fc2..65a33dd60b 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -364,7 +364,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) matrixService.leave($scope.room_id).then( function(response) { console.log("Left room "); - $location.url("rooms"); + $location.url("home"); }, function(error) { $scope.feedback = "Failed to leave room: " + error.data.error; -- cgit 1.4.1 From 31e7cec4868bbe98e2bfec04db47ec1d0bf3b8ed Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Fri, 22 Aug 2014 18:23:38 +0200 Subject: Added "Your name" as placeholder to help user understand what is this alone input box --- webclient/settings/settings.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/settings/settings.html b/webclient/settings/settings.html index 63b12c8f56..453a4fc35f 100644 --- a/webclient/settings/settings.html +++ b/webclient/settings/settings.html @@ -15,7 +15,7 @@
- +
-- cgit 1.4.1 From d2bb28d2df6ffe58db1a56e7aec85c34d9d1425f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 23 Aug 2014 20:45:00 +0100 Subject: very quick and dirty responsive design for iPhones --- webclient/app.css | 98 ++++++++++++++++++++++++++++++++++++++++------ webclient/index.html | 6 +-- webclient/login/login.html | 4 +- webclient/room/room.html | 30 +++++++------- webclient/rooms/rooms.html | 1 + webclient/user/user.html | 1 + 6 files changed, 110 insertions(+), 30 deletions(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index 207f35f5f3..6f320414b1 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -1,3 +1,71 @@ +/*** Mobile voodoo ***/ +@media all and (max-device-width: 640px) { + + #messageTableWrapper { + margin-right: 0px ! important; + } + + .leftBlock { + width: 8em ! important; + } + + #header, + #messageTable, + #wrapper, + #roomName, + #controls { + max-width: 640px ! important; + } + + #userIdCell, + #usersTableWrapper, + #extraControls { + display: none; + } + + #buttonsCell { + width: 60px ! important; + padding-left: 20px ! important; + } + + #roomLogo { + display: none; + } + + #roomName { + text-align: left ! important; + top: -35px ! important; + } + + .bubble { + font-size: 12px ! important; + height: 20px ! important; + } + + #page { + top: 35px ! important; + bottom: 70px ! important; + } + + #header, + #page { + margin: 5px ! important; + } + + #header { + padding: 5px ! important; + } + + /* stop zoom on select */ + select:focus, + textarea, + input + { + font-size: 16px ! important; + } + +} + body { font-family: "Myriad Pro", "Myriad", Helvetica, Arial, sans-serif; font-size: 12pt; @@ -17,7 +85,6 @@ h1 { left: 0px; right: 0px; margin: 20px; - margin: 20px; } #wrapper { @@ -32,8 +99,7 @@ h1 { text-align: right; top: -40px; position: absolute; - font-size: 16pt; - margin-bottom: 10px; + font-size: 16px; } #controlPanel { @@ -50,6 +116,10 @@ h1 { margin: auto; } +#buttonsCell { + width: 150px; +} + #inputBarTable { width: 100%; } @@ -111,13 +181,13 @@ h1 { color: #fff; margin: 2px; bottom: 0px; - font-size: 8pt; + font-size: 12px; word-break: break-all; } .userPresence { text-align: center; - font-size: 8pt; + font-size: 12px; color: #fff; background-color: #aaa; border-bottom: 1px #ddd solid; @@ -159,7 +229,7 @@ h1 { background-color: #fff; color: #888; font-weight: medium; - font-size: 8pt; + font-size: 12px; text-align: right; border-top: 1px #ddd solid; } @@ -277,7 +347,7 @@ h1 { .profile-avatar { width: 160px; height: 160px; - display:table-cell; + display: table-cell; vertical-align: middle; text-align: center; } @@ -293,13 +363,19 @@ h1 { } #user-displayname { - font-size: 16pt; + font-size: 24px; } /******************************/ -#header { - padding-left: 20px; - padding-right: 20px; +#header +{ + padding: 20px; + max-width: 1280px; + margin: auto; +} + +#logo, +#roomLogo { max-width: 1280px; margin: auto; } diff --git a/webclient/index.html b/webclient/index.html index 27d9208193..5b8e27fa6d 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -2,10 +2,12 @@ [matrix] - + + + @@ -36,8 +38,6 @@ - -

[matrix]

diff --git a/webclient/login/login.html b/webclient/login/login.html index b1488b37f0..4b2ea60928 100644 --- a/webclient/login/login.html +++ b/webclient/login/login.html @@ -1,4 +1,6 @@ -
{{ members[msg.user_id].displayname || msg.user_id }}
-
{{ (msg.content.hsob_ts || msg.ts) | date:'MMM d HH:mm:ss' }}
+
{{ (msg.content.hsob_ts || msg.ts) | date:'MMM d HH:mm' }}
- - - -
+ {{ state.user_id }} + + - - - +
- - Invite a user: - - - - - +
+ + Invite a user: + + + + +
+ {{ feedback }}
{{ state.stream_failure.data.error || "Connection failure" }} diff --git a/webclient/rooms/rooms.html b/webclient/rooms/rooms.html index 5e422bf83b..2a12cbc8ae 100644 --- a/webclient/rooms/rooms.html +++ b/webclient/rooms/rooms.html @@ -1,4 +1,5 @@
+

[matrix]

diff --git a/webclient/user/user.html b/webclient/user/user.html index 47db09d1ee..4c91c8a48a 100644 --- a/webclient/user/user.html +++ b/webclient/user/user.html @@ -1,4 +1,5 @@
+

[matrix]

-- cgit 1.4.1 From 3f08a7ad21cfa0529ed074a37617103e49c8c7e2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 23 Aug 2014 20:48:14 +0100 Subject: oops --- webclient/app.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'webclient') diff --git a/webclient/app.css b/webclient/app.css index 6f320414b1..7fe3cb3675 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -39,7 +39,7 @@ .bubble { font-size: 12px ! important; - height: 20px ! important; + min-height: 20px ! important; } #page { -- cgit 1.4.1 From 8b0473d5b9cb66ce69b152af3f2d61f9d8e78bb6 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Mon, 25 Aug 2014 10:25:43 +0200 Subject: Oops. Removed my NetBeans private folders --- webclient/nbproject/licenseheader.txt | 16 ---------------- webclient/nbproject/private/private.properties | 1 - webclient/nbproject/private/private.xml | 22 ---------------------- 3 files changed, 39 deletions(-) delete mode 100644 webclient/nbproject/licenseheader.txt delete mode 100644 webclient/nbproject/private/private.properties delete mode 100644 webclient/nbproject/private/private.xml (limited to 'webclient') diff --git a/webclient/nbproject/licenseheader.txt b/webclient/nbproject/licenseheader.txt deleted file mode 100644 index 36e6dcf181..0000000000 --- a/webclient/nbproject/licenseheader.txt +++ /dev/null @@ -1,16 +0,0 @@ -/* -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. -*/ - diff --git a/webclient/nbproject/private/private.properties b/webclient/nbproject/private/private.properties deleted file mode 100644 index 3b1a22e6c9..0000000000 --- a/webclient/nbproject/private/private.properties +++ /dev/null @@ -1 +0,0 @@ -browser=Chrome.INTEGRATED diff --git a/webclient/nbproject/private/private.xml b/webclient/nbproject/private/private.xml deleted file mode 100644 index 75bc70106a..0000000000 --- a/webclient/nbproject/private/private.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/matrix-service.js - file:/Users/manu/UC/matrix/github/synapse/webclient/app.css - file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/event-handler-service.js - file:/Users/manu/UC/matrix/github/synapse/webclient/app-controller.js - file:/Users/manu/UC/matrix/github/synapse/webclient/room/room.html - file:/Users/manu/UC/matrix/github/synapse/webclient/login/login.html - file:/Users/manu/UC/matrix/github/synapse/webclient/components/matrix/event-stream-service.js - file:/Users/manu/UC/matrix/github/synapse/webclient/components/fileUpload/file-upload-service.js - file:/Users/manu/UC/matrix/github/synapse/webclient/index.html - file:/Users/manu/UC/matrix/github/synapse/webclient/room/room-controller.js - file:/Users/manu/UC/matrix/github/synapse/webclient/rooms/rooms.html - file:/Users/manu/UC/matrix/github/synapse/webclient/app.js - file:/Users/manu/UC/matrix/github/synapse/webclient/rooms/rooms-controller.js - file:/Users/manu/UC/matrix/github/synapse/webclient/components/fileInput/file-input-directive.js - - - -- cgit 1.4.1 From 95839212a707f87d5927cde1187087afb7410b34 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Mon, 25 Aug 2014 11:35:33 +0200 Subject: The landing URL is now '#/' which actually points to homeController --- webclient/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'webclient') diff --git a/webclient/app.js b/webclient/app.js index e5d8513944..6cd50c5e54 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -45,7 +45,7 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', templateUrl: 'room/room.html', controller: 'RoomController' }). - when('/home', { + when('/', { templateUrl: 'home/home.html', controller: 'HomeController' }). @@ -58,7 +58,7 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', controller: 'UserController' }). otherwise({ - redirectTo: '/home' + redirectTo: '/' }); $provide.factory('AccessTokenInterceptor', ['$q', '$rootScope', -- cgit 1.4.1 From 5796232cb19927612957db3fcf4b77cd383187a6 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 26 Aug 2014 10:24:47 +0100 Subject: Adjusted webclient to use new state paths. Updated membership msg template to actually show the person invited. Factored out common membership functions in matrix service. --- synapse/rest/room.py | 3 +- .../components/matrix/event-handler-service.js | 4 -- webclient/components/matrix/matrix-service.js | 47 ++++++---------------- webclient/home/home-controller.js | 2 +- webclient/room/room-controller.js | 13 +++--- webclient/room/room.html | 2 +- 6 files changed, 24 insertions(+), 47 deletions(-) (limited to 'webclient') diff --git a/synapse/rest/room.py b/synapse/rest/room.py index a07e031984..2d681bd893 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -318,7 +318,8 @@ class RoomMemberListRestServlet(RestServlet): user_id=user.to_string()) for event in members["chunk"]: - target_user = self.hs.parse_userid(event["state_key"]) + # FIXME: should probably be state_key here, not user_id + target_user = self.hs.parse_userid(event["user_id"]) # Presence is an optional cache; don't fail if we can't fetch it try: presence_state = yield self.handlers.presence_handler.get_state( diff --git a/webclient/components/matrix/event-handler-service.js b/webclient/components/matrix/event-handler-service.js index b5eb73d92b..6ea0f58bc5 100644 --- a/webclient/components/matrix/event-handler-service.js +++ b/webclient/components/matrix/event-handler-service.js @@ -54,10 +54,6 @@ angular.module('eventHandlerService', []) } var handleMessage = function(event, isLiveEvent) { - if ("membership_target" in event.content) { - event.user_id = event.content.membership_target; - } - initRoom(event.room_id); if (isLiveEvent) { diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index d5738e01c8..b5b1815cf9 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -115,19 +115,7 @@ angular.module('matrixService', []) // Joins a room join: function(room_id) { - // The REST path spec - var path = "/rooms/$room_id/members/$user_id/state"; - - // Like the cmd client, escape room ids - room_id = encodeURIComponent(room_id); - - // Customize it - path = path.replace("$room_id", room_id); - path = path.replace("$user_id", config.user_id); - - return doRequest("PUT", path, undefined, { - membership: "join" - }); + return this.membershipChange(room_id, config.user_id, "join"); }, joinAlias: function(room_alias) { @@ -141,34 +129,23 @@ angular.module('matrixService', []) // Invite a user to a room invite: function(room_id, user_id) { - // The REST path spec - var path = "/rooms/$room_id/members/$user_id/state"; - - // Like the cmd client, escape room ids - room_id = encodeURIComponent(room_id); - - // Customize it - path = path.replace("$room_id", room_id); - path = path.replace("$user_id", user_id); - - return doRequest("PUT", path, undefined, { - membership: "invite" - }); + return this.membershipChange(room_id, user_id, "invite"); }, // Leaves a room leave: function(room_id) { - // The REST path spec - var path = "/rooms/$room_id/members/$user_id/state"; - - // Like the cmd client, escape room ids - room_id = encodeURIComponent(room_id); + return this.membershipChange(room_id, config.user_id, "leave"); + }, - // Customize it - path = path.replace("$room_id", room_id); - path = path.replace("$user_id", config.user_id); + membershipChange: function(room_id, user_id, membershipValue) { + // The REST path spec + var path = "/rooms/$room_id/state/m.room.member/$user_id"; + path = path.replace("$room_id", encodeURIComponent(room_id)); + path = path.replace("$user_id", encodeURIComponent(user_id)); - return doRequest("DELETE", path, undefined, undefined); + return doRequest("PUT", path, undefined, { + membership: membershipValue + }); }, // Retrieves the room ID corresponding to a room alias diff --git a/webclient/home/home-controller.js b/webclient/home/home-controller.js index 35d0ef1654..a5576759fa 100644 --- a/webclient/home/home-controller.js +++ b/webclient/home/home-controller.js @@ -41,7 +41,7 @@ angular.module('HomeController', ['matrixService', 'mFileInput', 'mFileUpload', $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") { + if (event.state_key === 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; diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 3311618825..f49deaa489 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -154,7 +154,10 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) var updateMemberList = function(chunk) { if (chunk.room_id != $scope.room_id) return; - var isNewMember = !(chunk.target_user_id in $scope.members); + // set target_user_id to keep things clear + var target_user_id = chunk.state_key; + + var isNewMember = !(target_user_id in $scope.members); if (isNewMember) { // FIXME: why are we copying these fields around inside chunk? if ("state" in chunk.content) { @@ -172,7 +175,7 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) if ("avatar_url" in chunk.content) { chunk.avatar_url = chunk.content.avatar_url; } - $scope.members[chunk.target_user_id] = chunk; + $scope.members[target_user_id] = chunk; /* // Stale code for explicitly hammering the homeserver for every displayname & avatar_url @@ -202,13 +205,13 @@ angular.module('RoomController', ['ngSanitize', 'mUtilities']) }); */ - if (chunk.target_user_id in $rootScope.presence) { - updatePresence($rootScope.presence[chunk.target_user_id]); + if (target_user_id in $rootScope.presence) { + updatePresence($rootScope.presence[target_user_id]); } } else { // selectively update membership else it will nuke the picture and displayname too :/ - var member = $scope.members[chunk.target_user_id]; + var member = $scope.members[target_user_id]; member.content.membership = chunk.content.membership; } } diff --git a/webclient/room/room.html b/webclient/room/room.html index 06ca63d2ea..c167819f15 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -44,7 +44,7 @@ {{ members[msg.user_id].displayname || msg.user_id }} {{ {"join": "joined", "leave": "left", "invite": "invited"}[msg.content.membership] }} - {{ msg.content.target_id || '' }} + {{ msg.content.membership === "invite" ? (msg.state_key || '') : '' }} -- cgit 1.4.1 From 9ff9caeb744bd75e033a45c429a39f8afe4754b1 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 26 Aug 2014 14:59:31 +0100 Subject: webclient: Updated to use /rooms/$roomid/[invite|join|leave] --- webclient/components/matrix/matrix-service.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'webclient') diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index b5b1815cf9..d376724e40 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -115,7 +115,7 @@ angular.module('matrixService', []) // Joins a room join: function(room_id) { - return this.membershipChange(room_id, config.user_id, "join"); + return this.membershipChange(room_id, undefined, "join"); }, joinAlias: function(room_alias) { @@ -134,18 +134,22 @@ angular.module('matrixService', []) // Leaves a room leave: function(room_id) { - return this.membershipChange(room_id, config.user_id, "leave"); + return this.membershipChange(room_id, undefined, "leave"); }, membershipChange: function(room_id, user_id, membershipValue) { // The REST path spec - var path = "/rooms/$room_id/state/m.room.member/$user_id"; + var path = "/rooms/$room_id/$membership"; path = path.replace("$room_id", encodeURIComponent(room_id)); - path = path.replace("$user_id", encodeURIComponent(user_id)); + path = path.replace("$membership", encodeURIComponent(membershipValue)); - return doRequest("PUT", path, undefined, { - membership: membershipValue - }); + var data = {}; + if (user_id !== undefined) { + data = { user_id: user_id }; + } + + // TODO: Use PUT with transaction IDs + return doRequest("POST", path, undefined, data); }, // Retrieves the room ID corresponding to a room alias -- cgit 1.4.1 From c21fcb3373b10e85fd2533570479cac6caf5da4e Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Tue, 26 Aug 2014 16:25:27 +0200 Subject: Determine and send user presence state --- webclient/app-controller.js | 14 +-- webclient/components/matrix/matrix-service.js | 17 ++++ webclient/components/matrix/presence-service.js | 113 ++++++++++++++++++++++++ webclient/index.html | 1 + 4 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 webclient/components/matrix/presence-service.js (limited to 'webclient') diff --git a/webclient/app-controller.js b/webclient/app-controller.js index 84cb94dc74..f210119e21 100644 --- a/webclient/app-controller.js +++ b/webclient/app-controller.js @@ -20,9 +20,9 @@ limitations under the License. 'use strict'; -angular.module('MatrixWebClientController', ['matrixService']) -.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService', 'eventStreamService', - function($scope, $location, $rootScope, matrixService, eventStreamService) { +angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'eventStreamService']) +.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventStreamService', + function($scope, $location, $rootScope, matrixService, mPresence, eventStreamService) { // Check current URL to avoid to display the logout button on the login page $scope.location = $location.path(); @@ -34,6 +34,7 @@ angular.module('MatrixWebClientController', ['matrixService']) if (matrixService.isUserLoggedIn()) { // eventStreamService.resume(); + mPresence.start(); } $scope.go = function(url) { @@ -42,9 +43,13 @@ angular.module('MatrixWebClientController', ['matrixService']) // Logs the user out $scope.logout = function() { + // kill the event stream eventStreamService.stop(); - + + // Do not update presence anymore + mPresence.stop(); + // Clean permanent data matrixService.setConfig({}); matrixService.saveConfig(); @@ -67,7 +72,6 @@ angular.module('MatrixWebClientController', ['matrixService']) } }; - }]); diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index d376724e40..237dd6d8a0 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -358,6 +358,23 @@ angular.module('matrixService', []) return false; } }, + + // Enum of presence state + presence: { + offline: "offline", + unavailable: "unavailable", + online: "online", + free_for_chat: "free_for_chat" + }, + + // Set the logged in user presence state + setUserPresence: function(presence) { + var path = "/presence/$user_id/status"; + path = path.replace("$user_id", config.user_id); + return doRequest("PUT", path, undefined, { + state: presence + }); + }, /****** Permanent storage of user information ******/ diff --git a/webclient/components/matrix/presence-service.js b/webclient/components/matrix/presence-service.js new file mode 100644 index 0000000000..6a1edcaf43 --- /dev/null +++ b/webclient/components/matrix/presence-service.js @@ -0,0 +1,113 @@ +/* + 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'; + +/* + * This service tracks user activity on the page to determine his presence state. + * Any state change will be sent to the Home Server. + */ +angular.module('mPresence', []) +.service('mPresence', ['$timeout', 'matrixService', function ($timeout, matrixService) { + + // Time in ms after that a user is considered as offline/away + var OFFLINE_TIME = 5 * 60000; // 5 mins + + // The current presence state + var state = undefined; + + var self =this; + var timer; + + /** + * Start listening the user activity to evaluate his presence state. + * Any state change will be sent to the Home Server. + */ + this.start = function() { + if (undefined === state) { + // The user is online if he moves the mouser or press a key + document.onmousemove = resetTimer; + document.onkeypress = resetTimer; + + resetTimer(); + } + }; + + /** + * Stop tracking user activity + */ + this.stop = function() { + if (timer) { + $timeout.cancel(timer); + timer = undefined; + } + state = undefined; + }; + + /** + * Get the current presence state. + * @returns {matrixService.presence} the presence state + */ + this.getState = function() { + return state; + }; + + /** + * Set the presence state. + * If the state has changed, the Home Server will be notified. + * @param {matrixService.presence} newState the new presence state + */ + this.setState = function(newState) { + if (newState !== state) { + console.log("mPresence - New state: " + newState); + + state = newState; + + // Inform the HS on the new user state + matrixService.setUserPresence(state).then( + function() { + + }, + function(error) { + console.log("mPresence - Failed to send new presence state: " + JSON.stringify(error)); + }); + } + }; + + /** + * Callback called when the user made no action on the page for OFFLINE_TIME ms. + * @private + */ + function onOfflineTimerFire() { + self.setState(matrixService.presence.offline); + } + + /** + * Callback called when the user made an action on the page + * @private + */ + function resetTimer() { + // User is still here + self.setState(matrixService.presence.online); + + // Re-arm the timer + $timeout.cancel(timer); + timer = $timeout(onOfflineTimerFire, OFFLINE_TIME); + } + +}]); + + diff --git a/webclient/index.html b/webclient/index.html index 938d70c86d..6031036e9a 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -26,6 +26,7 @@ + -- cgit 1.4.1 From bcf8eb687a35d634b004985fd858a660e8ccb9e9 Mon Sep 17 00:00:00 2001 From: Emmanuel ROHEE Date: Tue, 26 Aug 2014 16:57:29 +0200 Subject: Avoid double call of refresh at app startup --- webclient/home/home-controller.js | 10 ++++++---- webclient/home/home.html | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'webclient') diff --git a/webclient/home/home-controller.js b/webclient/home/home-controller.js index a5576759fa..867ae522a6 100644 --- a/webclient/home/home-controller.js +++ b/webclient/home/home-controller.js @@ -76,9 +76,9 @@ angular.module('HomeController', ['matrixService', 'mFileInput', 'mFileUpload', return data; }; - $scope.refresh = function() { + var refresh = function() { // List all rooms joined or been invited to - matrixService.rooms().then( + matrixService.rooms(1,true).then( function(response) { var data = assignRoomAliases(response.data.rooms); $scope.feedback = "Success"; @@ -118,7 +118,7 @@ angular.module('HomeController', ['matrixService', 'mFileInput', 'mFileUpload', response.data.room_id); matrixService.createRoomIdToAliasMapping( response.data.room_id, response.data.room_alias); - $scope.refresh(); + refresh(); }, function(error) { $scope.feedback = "Failure: " + error.data; @@ -158,5 +158,7 @@ angular.module('HomeController', ['matrixService', 'mFileInput', 'mFileUpload', ); }; - $scope.refresh(); + $scope.onInit = function() { + refresh(); + }; }]); diff --git a/webclient/home/home.html b/webclient/home/home.html index 4818d414b6..4084f4c388 100644 --- a/webclient/home/home.html +++ b/webclient/home/home.html @@ -1,4 +1,4 @@ -
+
-- cgit 1.4.1