diff --git a/skins/base/views/organisms/RoomView.js b/skins/base/views/organisms/RoomView.js
index 88adfdaadf..5878e881e9 100644
--- a/skins/base/views/organisms/RoomView.js
+++ b/skins/base/views/organisms/RoomView.js
@@ -71,6 +71,20 @@ module.exports = React.createClass({
mx_RoomView_scrollheader: true,
loading: this.state.paginating
});
+
+ var statusBar = (
+
+ );
+
+ var typingString = this.getWhoIsTypingString();
+ if (typingString) {
+ statusBar = (
+
+ {typingString}
+
+ );
+ }
+
return (
@@ -88,6 +102,7 @@ module.exports = React.createClass({
diff --git a/src/WhoIsTyping.js b/src/WhoIsTyping.js
new file mode 100644
index 0000000000..4fb5399027
--- /dev/null
+++ b/src/WhoIsTyping.js
@@ -0,0 +1,49 @@
+var MatrixClientPeg = require("./MatrixClientPeg");
+
+module.exports = {
+ usersTypingApartFromMe: function(room) {
+ return this.usersTyping(
+ room, [MatrixClientPeg.get().credentials.userId]
+ );
+ },
+
+ /**
+ * Given a Room object and, optionally, a list of userID strings
+ * to exclude, return a list of user objects who are typing.
+ */
+ usersTyping: function(room, exclude) {
+ var whoIsTyping = [];
+
+ if (exclude === undefined) {
+ exclude = [];
+ }
+
+ var memberKeys = Object.keys(room.currentState.members);
+ for (var i = 0; i < memberKeys.length; ++i) {
+ var userId = memberKeys[i];
+
+ if (room.currentState.members[userId].typing) {
+ if (exclude.indexOf(userId) == -1) {
+ whoIsTyping.push(room.currentState.members[userId]);
+ }
+ }
+ }
+
+ return whoIsTyping;
+ },
+
+ whoIsTypingString: function(room) {
+ var whoIsTyping = this.usersTypingApartFromMe(room);
+ if (whoIsTyping.length == 0) {
+ return null;
+ } else if (whoIsTyping.length == 1) {
+ return whoIsTyping[0].name + ' is typing';
+ } else {
+ var names = whoIsTyping.map(function(m) {
+ return m.name;
+ });
+ var lastPerson = names.shift();
+ return names.join(', ') + ' and ' + lastPerson + ' are typing';
+ }
+ }
+}
diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js
index f73b5c8f46..59807b63fe 100644
--- a/src/controllers/organisms/RoomView.js
+++ b/src/controllers/organisms/RoomView.js
@@ -20,6 +20,7 @@ var MatrixClientPeg = require("../../MatrixClientPeg");
var React = require("react");
var q = require("q");
var ContentMessages = require("../../ContentMessages");
+var WhoIsTyping = require("../../WhoIsTyping");
var dis = require("../../dispatcher");
@@ -51,6 +52,7 @@ module.exports = {
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().on("Room.name", this.onRoomName);
+ MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping);
this.atBottom = true;
},
@@ -64,6 +66,7 @@ module.exports = {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
+ MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping);
}
},
@@ -118,6 +121,10 @@ module.exports = {
}
},
+ onRoomMemberTyping: function(ev, member) {
+ this.forceUpdate();
+ },
+
componentDidMount: function() {
if (this.refs.messageWrapper) {
var messageWrapper = this.refs.messageWrapper.getDOMNode();
@@ -236,6 +243,10 @@ module.exports = {
}
},
+ getWhoIsTypingString() {
+ return WhoIsTyping.whoIsTypingString(this.state.room);
+ },
+
getEventTiles: function() {
var ret = [];
var count = 0;