Merge pull request #1246 from matrix-org/luke/feature-async-pills
Get user pill profile remote data and show unrecognised rooms as links
This commit is contained in:
commit
b372e5d55d
1 changed files with 105 additions and 31 deletions
|
@ -28,7 +28,7 @@ const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN);
|
|||
// HttpUtils transformTags to relative links
|
||||
const REGEX_LOCAL_MATRIXTO = /^#\/(?:user|room)\/(([\#\!\@\+]).*)$/;
|
||||
|
||||
export default React.createClass({
|
||||
const Pill = React.createClass({
|
||||
statics: {
|
||||
isPillUrl: (url) => {
|
||||
return !!REGEX_MATRIXTO.exec(url);
|
||||
|
@ -36,6 +36,8 @@ export default React.createClass({
|
|||
isMessagePillUrl: (url) => {
|
||||
return !!REGEX_LOCAL_MATRIXTO.exec(url);
|
||||
},
|
||||
TYPE_USER_MENTION: 'TYPE_USER_MENTION',
|
||||
TYPE_ROOM_MENTION: 'TYPE_ROOM_MENTION',
|
||||
},
|
||||
|
||||
props: {
|
||||
|
@ -47,10 +49,22 @@ export default React.createClass({
|
|||
room: PropTypes.instanceOf(Room),
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
||||
getInitialState() {
|
||||
return {
|
||||
// ID/alias of the room/user
|
||||
resourceId: null,
|
||||
// Type of pill
|
||||
pillType: null,
|
||||
|
||||
// The member related to the user pill
|
||||
member: null,
|
||||
// The room related to the room pill
|
||||
room: null,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount() {
|
||||
this._unmounted = false;
|
||||
let regex = REGEX_MATRIXTO;
|
||||
if (this.props.inMessage) {
|
||||
regex = REGEX_LOCAL_MATRIXTO;
|
||||
|
@ -60,46 +74,104 @@ export default React.createClass({
|
|||
// resource and prefix will be undefined instead of throwing
|
||||
const matrixToMatch = regex.exec(this.props.url) || [];
|
||||
|
||||
const resource = matrixToMatch[1]; // The room/user ID
|
||||
const resourceId = matrixToMatch[1]; // The room/user ID
|
||||
const prefix = matrixToMatch[2]; // The first character of prefix
|
||||
|
||||
// Default to the room/user ID
|
||||
let linkText = resource;
|
||||
const pillType = {
|
||||
'@': Pill.TYPE_USER_MENTION,
|
||||
'#': Pill.TYPE_ROOM_MENTION,
|
||||
'!': Pill.TYPE_ROOM_MENTION,
|
||||
}[prefix];
|
||||
|
||||
const isUserPill = prefix === '@';
|
||||
const isRoomPill = prefix === '#' || prefix === '!';
|
||||
let member;
|
||||
let room;
|
||||
switch (pillType) {
|
||||
case Pill.TYPE_USER_MENTION: {
|
||||
const localMember = this.props.room.getMember(resourceId);
|
||||
member = localMember;
|
||||
if (!localMember) {
|
||||
member = new RoomMember(null, resourceId);
|
||||
this.doProfileLookup(resourceId, member);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Pill.TYPE_ROOM_MENTION: {
|
||||
const localRoom = resourceId[0] === '#' ?
|
||||
MatrixClientPeg.get().getRooms().find((r) => {
|
||||
return r.getAliases().includes(resourceId);
|
||||
}) : MatrixClientPeg.get().getRoom(resourceId);
|
||||
room = localRoom;
|
||||
if (!localRoom) {
|
||||
// TODO: This would require a new API to resolve a room alias to
|
||||
// a room avatar and name.
|
||||
// this.doRoomProfileLookup(resourceId, member);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
this.setState({resourceId, pillType, member, room});
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this._unmounted = true;
|
||||
},
|
||||
|
||||
doProfileLookup: function(userId, member) {
|
||||
MatrixClientPeg.get().getProfileInfo(userId).then((resp) => {
|
||||
if (this._unmounted) {
|
||||
return;
|
||||
}
|
||||
member.name = resp.displayname;
|
||||
member.rawDisplayName = resp.displayname;
|
||||
member.events.member = {
|
||||
getContent: () => {
|
||||
return {avatar_url: resp.avatar_url};
|
||||
},
|
||||
};
|
||||
this.setState({member});
|
||||
}).catch((err) => {
|
||||
console.error('Could not retrieve profile data for ' + userId + ':', err);
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
||||
|
||||
const resource = this.state.resourceId;
|
||||
|
||||
let avatar = null;
|
||||
let linkText = resource;
|
||||
let pillClass;
|
||||
let userId;
|
||||
if (isUserPill) {
|
||||
// If this user is not a member of this room, default to the empty member
|
||||
// TODO: This could be improved by doing an async profile lookup
|
||||
const member = this.props.room.getMember(resource) ||
|
||||
new RoomMember(null, resource);
|
||||
if (member) {
|
||||
userId = member.userId;
|
||||
linkText = member.rawDisplayName;
|
||||
avatar = <MemberAvatar member={member} width={16} height={16}/>;
|
||||
switch (this.state.pillType) {
|
||||
case Pill.TYPE_USER_MENTION: {
|
||||
// If this user is not a member of this room, default to the empty member
|
||||
const member = this.state.member;
|
||||
if (member) {
|
||||
userId = member.userId;
|
||||
linkText = member.name;
|
||||
avatar = <MemberAvatar member={member} width={16} height={16}/>;
|
||||
pillClass = 'mx_UserPill';
|
||||
}
|
||||
}
|
||||
} else if (isRoomPill) {
|
||||
const room = prefix === '#' ?
|
||||
MatrixClientPeg.get().getRooms().find((r) => {
|
||||
return r.getAliases().includes(resource);
|
||||
}) : MatrixClientPeg.get().getRoom(resource);
|
||||
|
||||
if (room) {
|
||||
linkText = (room ? getDisplayAliasForRoom(room) : null) || resource;
|
||||
avatar = <RoomAvatar room={room} width={16} height={16}/>;
|
||||
break;
|
||||
case Pill.TYPE_ROOM_MENTION: {
|
||||
const room = this.state.room;
|
||||
if (room) {
|
||||
linkText = (room ? getDisplayAliasForRoom(room) : null) || resource;
|
||||
avatar = <RoomAvatar room={room} width={16} height={16}/>;
|
||||
pillClass = 'mx_RoomPill';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const classes = classNames({
|
||||
"mx_UserPill": isUserPill,
|
||||
"mx_RoomPill": isRoomPill,
|
||||
const classes = classNames(pillClass, {
|
||||
"mx_UserPill_me": userId === MatrixClientPeg.get().credentials.userId,
|
||||
});
|
||||
|
||||
if ((isUserPill || isRoomPill) && avatar) {
|
||||
if (this.state.pillType) {
|
||||
return this.props.inMessage ?
|
||||
<a className={classes} href={this.props.url} title={resource}>
|
||||
{avatar}
|
||||
|
@ -115,3 +187,5 @@ export default React.createClass({
|
|||
}
|
||||
},
|
||||
});
|
||||
|
||||
export default Pill;
|
||||
|
|
Loading…
Reference in a new issue