diff --git a/lib/client.js b/lib/client.js
index 3db7b6127..d0a32fa1d 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -559,44 +559,6 @@ module.exports.MatrixClient.prototype = {
}
},
- /*
- * Helper method for retrieving the name of a user suitable for display
- * in the UI in the context of a room - i.e. disambiguating from any
- * other users in the room.
- * XXX: This could perhaps also be generated serverside, perhaps by just passing
- * a 'disambiguate' flag down on membership entries which have ambiguous
- * displaynames?
- * @param {String} userId ID of the user whose name is to be resolved
- * @param {String} roomId ID of room to be used as the context for
- * resolving the name.
- * @return {String} human-readable name of the user.
- */
- getFriendlyDisplayName: function(userId, roomId) {
- // we need a store to track the inputs for calculating display names
- if (!this.store) { return userId; }
-
- var displayName;
- var memberEvent = this.store.getStateEvent(roomId, 'm.room.member', userId);
- if (memberEvent && memberEvent.event.content.displayname) {
- displayName = memberEvent.event.content.displayname;
- }
- else {
- return userId;
- }
-
- var members = this.store.getStateEvents(roomId, 'm.room.member')
- .filter(function(event) {
- return event.event.content.displayname === displayName;
- });
-
- if (members.length > 1) {
- return displayName + " (" + userId + ")";
- }
- else {
- return displayName;
- }
- },
-
/**
* High level helper method to call initialSync, emit the resulting events,
* and then start polling the eventStream for new events.
diff --git a/lib/models/event.js b/lib/models/event.js
index bc775f2f2..c78daf171 100644
--- a/lib/models/event.js
+++ b/lib/models/event.js
@@ -85,10 +85,10 @@ module.exports.MatrixEvent.prototype = {
/**
* Get the event content JSON.
- * @return {Object} The event content JSON.
+ * @return {Object} The event content JSON, or an empty object.
*/
getContent: function() {
- return this.event.content;
+ return this.event.content || {};
},
/**
diff --git a/lib/models/room-member.js b/lib/models/room-member.js
index 7dbced018..6d81c21f6 100644
--- a/lib/models/room-member.js
+++ b/lib/models/room-member.js
@@ -2,6 +2,7 @@
/**
* @module models/room-member
*/
+var utils = require("../utils");
/**
* Construct a new room member.
@@ -25,10 +26,40 @@ function RoomMember(event) {
this.userId = event.getSender();
this.event = event;
this.typing = false;
- this.name = this.userId;
+ this.name = this.calculateDisplayName();
this.powerLevel = 0;
this.powerLevelNorm = 0;
}
+RoomMember.prototype = {
+ /**
+ * Calculates the display name for this room member.
+ * @param {RoomState} roomState Optional. The room state to take into
+ * account when calculating (e.g. for disambiguating users with the same
+ * name).
+ * @return {string} The calculated display name.
+ */
+ calculateDisplayName: function(roomState) {
+ var displayName = this.event.getContent().displayname;
+ if (!displayName) {
+ return this.userId;
+ }
+ if (!roomState) {
+ return displayName;
+ }
+
+ var stateEvents = utils.filter(
+ roomState.getStateEvents("m.room.member"),
+ function(event) {
+ return event.getContent().displayname === displayName;
+ }
+ );
+ if (stateEvents.length > 1) {
+ return displayName + " (" + this.userId + ")";
+ }
+
+ return displayName;
+ }
+};
/**
* The RoomMember class.
diff --git a/lib/models/room-state.js b/lib/models/room-state.js
index 439bda256..98741e5dd 100644
--- a/lib/models/room-state.js
+++ b/lib/models/room-state.js
@@ -2,6 +2,7 @@
/**
* @module models/room-state
*/
+var utils = require("../utils");
/**
* Construct room state.
@@ -21,6 +22,28 @@ function RoomState() {
};
this.paginationToken = null;
}
+RoomState.prototype = {
+ /**
+ * Get state events from the state of the room.
+ * @param {string} eventType The event type of the state event.
+ * @param {string} stateKey Optional. The state_key of the state event. If
+ * this is undefined
then all matching state events will be
+ * returned.
+ * @return {MatrixEvent[]|MatrixEvent} A list of events if state_key was
+ * undefined
, else a single event (or null if no match found).
+ */
+ getStateEvents: function(eventType, stateKey) {
+ if (!this.stateEvents[eventType]) {
+ // no match
+ return stateKey ? null : [];
+ }
+ if (!stateKey) { // return all values
+ return utils.values(this.stateEvents[eventType]);
+ }
+ var event = this.stateEvents[eventType][stateKey];
+ return event ? event : null;
+ }
+};
/**
* The RoomState class.
diff --git a/lib/utils.js b/lib/utils.js
index 58ca58819..eeceeb7e5 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -53,6 +53,52 @@ module.exports.map = function(array, fn) {
return results;
};
+/**
+ * Applies a filter function to the given array.
+ * @param {Array} array The array to apply the function to.
+ * @param {Function} fn The function that will be invoked for each element in
+ * the array. It should return true to keep the element. The function signature
+ * looks like fn(element, index, array){...}
.
+ * @return {Array} A new array with the results of the function.
+ */
+module.exports.filter = function(array, fn) {
+ var results = [];
+ for (var i = 0; i < array.length; i++) {
+ if (fn(array[i], i, array)) {
+ results.push(results);
+ }
+ }
+ return results;
+};
+
+/**
+ * Get the keys for an object. Same as Object.keys()
.
+ * @param {Object} obj The object to get the keys for.
+ * @return {string[]} The keys of the object.
+ */
+module.exports.keys = function(obj) {
+ var keys = [];
+ for (var key in obj) {
+ if (!obj.hasOwnProperty(key)) { continue; }
+ keys.push(key);
+ }
+ return keys;
+};
+
+/**
+ * Get the values for an object.
+ * @param {Object} obj The object to get the values for.
+ * @return {Array<*>} The values of the object.
+ */
+module.exports.values = function(obj) {
+ var values = [];
+ for (var key in obj) {
+ if (!obj.hasOwnProperty(key)) { continue; }
+ values.push(obj[key]);
+ }
+ return values;
+};
+
/**
* Checks if the given thing is a function.
* @param {*} value The thing to check.