forked from Ivasoft/mattermost-mobile
RN-74 Added channel links (#620)
* Updated AtMention component to match web app * RN-74 Added channel links * Updated yarn.lock
This commit is contained in:
@@ -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 <Text style={this.props.textStyle}>{'@' + this.props.mentionName}</Text>;
|
||||
}
|
||||
|
||||
const suffix = this.props.mentionName.substring(username.length);
|
||||
|
||||
return (
|
||||
|
||||
83
app/components/channel_link/channel_link.js
Normal file
83
app/components/channel_link/channel_link.js
Normal file
@@ -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 <Text style={this.props.textStyle}>{'~' + this.props.channelName}</Text>;
|
||||
}
|
||||
|
||||
const suffix = this.props.channelName.substring(channel.name.length);
|
||||
|
||||
return (
|
||||
<Text style={this.props.textStyle}>
|
||||
<Text
|
||||
style={this.props.linkStyle}
|
||||
onPress={this.handlePress}
|
||||
>
|
||||
{channel.display_name}
|
||||
</Text>
|
||||
{suffix}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
29
app/components/channel_link/index.js
Normal file
29
app/components/channel_link/index.js
Normal file
@@ -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);
|
||||
@@ -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 (
|
||||
<ChannelLink
|
||||
linkStyle={this.props.textStyles.link}
|
||||
textStyle={this.computeTextStyle(this.props.baseTextStyle, context)}
|
||||
channelName={channelName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderEmoji = ({context, emojiName, literal}) => {
|
||||
let size;
|
||||
const headingType = context.find((type) => type.startsWith('heading'));
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user