diff --git a/app/components/at_mention/at_mention.js b/app/components/at_mention/at_mention.js
index eca3a4c76..ae2a87e5b 100644
--- a/app/components/at_mention/at_mention.js
+++ b/app/components/at_mention/at_mention.js
@@ -1,13 +1,13 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import React, {PureComponent} from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import {Text} from 'react-native';
import CustomPropTypes from 'app/constants/custom_prop_types';
-export default class AtMention extends PureComponent {
+export default class AtMention extends React.PureComponent {
static propTypes = {
mentionName: PropTypes.string.isRequired,
mentionStyle: CustomPropTypes.Style,
@@ -15,12 +15,28 @@ export default class AtMention extends PureComponent {
usersByUsername: PropTypes.object.isRequired
};
- getUsernameFromMentionName = () => {
- let mentionName = this.props.mentionName;
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ username: this.getUsernameFromMentionName(props)
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.mentionName !== this.props.mentionName || nextProps.usersByUsername !== this.props.usersByUsername) {
+ this.setState({
+ username: this.getUsernameFromMentionName(nextProps)
+ });
+ }
+ }
+
+ getUsernameFromMentionName(props) {
+ let mentionName = props.mentionName;
while (mentionName.length > 0) {
- if (this.props.usersByUsername[mentionName]) {
- return this.props.usersByUsername[mentionName].username;
+ if (props.usersByUsername[mentionName]) {
+ return props.usersByUsername[mentionName].username;
}
// Repeatedly trim off trailing punctuation in case this is at the end of a sentence
@@ -31,12 +47,16 @@ export default class AtMention extends PureComponent {
}
}
- // Just assume this is a mention for a user that we don't have
- return mentionName;
+ return '';
}
render() {
- const username = this.getUsernameFromMentionName();
+ const username = this.state.username;
+
+ if (!username) {
+ return {'@' + this.props.mentionName};
+ }
+
const suffix = this.props.mentionName.substring(username.length);
return (
diff --git a/app/components/channel_link/channel_link.js b/app/components/channel_link/channel_link.js
new file mode 100644
index 000000000..3a346601e
--- /dev/null
+++ b/app/components/channel_link/channel_link.js
@@ -0,0 +1,83 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Text} from 'react-native';
+
+import CustomPropTypes from 'app/constants/custom_prop_types';
+
+export default class ChannelLink extends React.PureComponent {
+ static propTypes = {
+ channelName: PropTypes.string.isRequired,
+ linkStyle: CustomPropTypes.Style,
+ textStyle: CustomPropTypes.Style,
+ channelsByName: PropTypes.object.isRequired,
+ actions: PropTypes.shape({
+ handleSelectChannel: PropTypes.func.isRequired,
+ setChannelDisplayName: PropTypes.func.isRequired
+ }).isRequired
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ channel: this.getChannelFromChannelName(props)
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.channelName !== this.props.channelName || nextProps.channelsByName !== this.props.channelsByName) {
+ this.setState({
+ channel: this.getChannelFromChannelName(nextProps)
+ });
+ }
+ }
+
+ getChannelFromChannelName(props) {
+ let channelName = props.channelName;
+
+ while (channelName.length > 0) {
+ if (props.channelsByName[channelName]) {
+ return props.channelsByName[channelName];
+ }
+
+ // Repeatedly trim off trailing punctuation in case this is at the end of a sentence
+ if ((/[_-]$/).test(channelName)) {
+ channelName = channelName.substring(0, channelName.length - 1);
+ } else {
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ handlePress = () => {
+ this.props.actions.setChannelDisplayName(this.state.channel.display_name);
+ this.props.actions.handleSelectChannel(this.state.channel.id);
+ }
+
+ render() {
+ const channel = this.state.channel;
+
+ if (!channel) {
+ return {'~' + this.props.channelName};
+ }
+
+ const suffix = this.props.channelName.substring(channel.name.length);
+
+ return (
+
+
+ {channel.display_name}
+
+ {suffix}
+
+ );
+ }
+}
diff --git a/app/components/channel_link/index.js b/app/components/channel_link/index.js
new file mode 100644
index 000000000..9d6c9d053
--- /dev/null
+++ b/app/components/channel_link/index.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+
+import {getChannelsNameMapInCurrentTeam} from 'mattermost-redux/selectors/entities/channels';
+
+import {handleSelectChannel, setChannelDisplayName} from 'app/actions/views/channel';
+
+import ChannelLink from './channel_link';
+
+function mapStateToProps(state, ownProps) {
+ return {
+ channelsByName: getChannelsNameMapInCurrentTeam(state),
+ ...ownProps
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ handleSelectChannel,
+ setChannelDisplayName
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChannelLink);
diff --git a/app/components/markdown/index.js b/app/components/markdown/index.js
index 82212b969..00cff842a 100644
--- a/app/components/markdown/index.js
+++ b/app/components/markdown/index.js
@@ -13,6 +13,7 @@ import {
} from 'react-native';
import AtMention from 'app/components/at_mention';
+import ChannelLink from 'app/components/channel_link';
import Emoji from 'app/components/emoji';
import CustomPropTypes from 'app/constants/custom_prop_types';
import {concatStyles} from 'app/utils/theme';
@@ -77,6 +78,7 @@ export default class Markdown extends React.PureComponent {
link: MarkdownLink,
image: this.renderImage,
atMention: this.renderAtMention,
+ channelLink: this.renderChannelLink,
emoji: this.renderEmoji,
paragraph: this.renderParagraph,
@@ -134,6 +136,16 @@ export default class Markdown extends React.PureComponent {
);
}
+ renderChannelLink = ({context, channelName}) => {
+ return (
+
+ );
+ }
+
renderEmoji = ({context, emojiName, literal}) => {
let size;
const headingType = context.find((type) => type.startsWith('heading'));
diff --git a/package.json b/package.json
index a8f64f4ce..6664c68f4 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,8 @@
"private": true,
"dependencies": {
"babel-polyfill": "6.23.0",
- "commonmark": "hmhealey/commonmark.js#0e1c57aff4e0729e12ae1453fadc6c8bfd86cf96",
- "commonmark-react-renderer": "hmhealey/commonmark-react-renderer#1cec47814455f2eb3858864334eb4300b5103523",
+ "commonmark": "hmhealey/commonmark.js#10bc18c0c8054088c0ec4737a8766c6b5794a323",
+ "commonmark-react-renderer": "hmhealey/commonmark-react-renderer#7be9f10cdb3408a64366a20e60975edff0b5c710",
"deep-equal": "1.0.1",
"intl": "1.2.5",
"mattermost-redux": "mattermost/mattermost-redux#master",
diff --git a/yarn.lock b/yarn.lock
index 5811899e9..1fb0f70fb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1512,9 +1512,9 @@ commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
-commonmark-react-renderer@hmhealey/commonmark-react-renderer#1cec47814455f2eb3858864334eb4300b5103523:
+commonmark-react-renderer@hmhealey/commonmark-react-renderer#7be9f10cdb3408a64366a20e60975edff0b5c710:
version "4.3.2"
- resolved "https://codeload.github.com/hmhealey/commonmark-react-renderer/tar.gz/1cec47814455f2eb3858864334eb4300b5103523"
+ resolved "https://codeload.github.com/hmhealey/commonmark-react-renderer/tar.gz/7be9f10cdb3408a64366a20e60975edff0b5c710"
dependencies:
in-publish "^2.0.0"
lodash.assign "^4.2.0"
@@ -1522,9 +1522,9 @@ commonmark-react-renderer@hmhealey/commonmark-react-renderer#1cec47814455f2eb385
pascalcase "^0.1.1"
xss-filters "^1.2.6"
-commonmark@hmhealey/commonmark.js#0e1c57aff4e0729e12ae1453fadc6c8bfd86cf96:
+commonmark@hmhealey/commonmark.js#10bc18c0c8054088c0ec4737a8766c6b5794a323:
version "0.27.0"
- resolved "https://codeload.github.com/hmhealey/commonmark.js/tar.gz/0e1c57aff4e0729e12ae1453fadc6c8bfd86cf96"
+ resolved "https://codeload.github.com/hmhealey/commonmark.js/tar.gz/10bc18c0c8054088c0ec4737a8766c6b5794a323"
dependencies:
entities "~ 1.1.1"
mdurl "~ 1.0.1"