diff --git a/src/RichText.js b/src/RichText.js index f2f2d533a8..3cd0f5ec59 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -113,31 +113,6 @@ let emojiDecorator = { * Returns a composite decorator which has access to provided scope. */ export function getScopedRTDecorators(scope: any): CompositeDecorator { - let MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); - - let usernameDecorator = { - strategy: (contentBlock, callback) => { - findWithRegex(USERNAME_REGEX, contentBlock, callback); - }, - component: (props) => { - let member = scope.room.getMember(props.children[0].props.text); - // unused until we make these decorators immutable (autocomplete needed) - let name = member ? member.name : null; - let avatar = member ? : null; - return {avatar}{props.children}; - } - }; - - let roomDecorator = { - strategy: (contentBlock, callback) => { - findWithRegex(ROOM_REGEX, contentBlock, callback); - }, - component: (props) => { - return {props.children}; - } - }; - - // TODO Re-enable usernameDecorator and roomDecorator return [emojiDecorator]; } diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 2c50a94a6a..ab1d67a218 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -30,6 +30,8 @@ import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; import { _t } from '../../../languageHandler'; import UserSettingsStore from "../../../UserSettingsStore"; +import MatrixClientPeg from '../../../MatrixClientPeg'; +import {RoomMember} from 'matrix-js-sdk'; linkifyMatrix(linkify); @@ -80,6 +82,10 @@ module.exports = React.createClass({ componentDidMount: function() { this._unmounted = false; + // pillifyLinks BEFORE linkifyElement because plain room/user URLs in the composer + // are still sent as plaintext URLs. If these are ever pillified in the composer, + // we should be pillify them here by doing the linkifying BEFORE the pillifying. + this.pillifyLinks(this.refs.content.children); linkifyElement(this.refs.content, linkifyMatrix.options); this.calculateUrlPreview(); @@ -162,6 +168,55 @@ module.exports = React.createClass({ } }, + pillifyLinks: function(nodes) { + const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); + const RoomAvatar = sdk.getComponent('avatars.RoomAvatar'); + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (node.tagName === "A" && node.getAttribute("href")) { + const href = node.getAttribute("href"); + // HtmlUtils transforms `matrix.to` links to local links, so match against + // user or room app links. + const match = /^#\/(user|room)\/(.*)$/.exec(href) || []; + const resourceType = match[1]; // "user" or "room" + const resourceId = match[2]; // user ID or room ID + if (match && resourceType && resourceId) { + let avatar; + let roomId; + let room; + let member; + switch (resourceType) { + case "user": + roomId = this.props.mxEvent.getRoomId(); + room = MatrixClientPeg.get().getRoom(roomId); + member = room.getMember(resourceId) || + new RoomMember(null, resourceId); + avatar = ; + break; + case "room": + room = resourceId[0] === '#' ? + MatrixClientPeg.get().getRooms().find((r) => { + return r.getCanonicalAlias() === resourceId; + }) : MatrixClientPeg.get().getRoom(resourceId); + if (room) { + avatar = ; + } + break; + } + if (avatar) { + const avatarContainer = document.createElement('span'); + node.className = "mx_MTextBody_pill " + + (resourceType === "user" ? "mx_UserPill" : "mx_RoomPill"); + ReactDOM.render(avatar, avatarContainer); + node.insertBefore(avatarContainer, node.firstChild); + } + } + } else if (node.children && node.children.length) { + this.pillifyLinks(node.children); + } + } + }, + findLinks: function(nodes) { var links = [];