From a2257aeb0bc183b0c98c4229e4148457dca77540 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 8 Jun 2015 12:21:23 +0100 Subject: [PATCH] Move getFriendlyDisplayName to RoomMember class. Add more utlity functions. --- lib/client.js | 38 -------------------------------- lib/models/event.js | 4 ++-- lib/models/room-member.js | 33 +++++++++++++++++++++++++++- lib/models/room-state.js | 23 ++++++++++++++++++++ lib/utils.js | 46 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 41 deletions(-) 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.