...
 
Commits (3)
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {getChannelsNameMapInCurrentTeam} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
import {getEmojiMap} from 'selectors/emojis';
import {getSiteURL} from 'utils/url.jsx';
import PostMarkdown from './post_markdown';
const getChannelNamesMap = createSelector(
getChannelsNameMapInCurrentTeam,
(state, props) => props,
(channelNamesMap, props) => {
if (props && props.channel_mentions) {
return Object.assign({}, props.channel_mentions, channelNamesMap);
}
return channelNamesMap;
}
);
function mapStateToProps(state, ownProps) {
return {
channelNamesMap: getChannelNamesMap(state),
emojis: getEmojiMap(state),
mentionKeys: ownProps.mentionKeys || getCurrentUserMentionKeys(state),
siteURL: getSiteURL(),
team: getCurrentTeam(state)
};
}
export default connect(mapStateToProps)(PostMarkdown);
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import PropTypes from 'prop-types';
import React from 'react';
import * as PostUtils from 'utils/post_utils.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
import {renderSystemMessage} from './system_message_helpers.jsx';
export default class PostMarkdown extends React.PureComponent {
static propTypes = {
/*
* An object mapping channel names to channels for the current team
*/
channelNamesMap: PropTypes.object.isRequired,
/*
* An object mapping emoji names to emojis including both custom and system emojis
*/
emojis: PropTypes.object.isRequired,
/*
* Whether or not this text is part of the RHS
*/
isRHS: PropTypes.bool,
/*
* An array of words that can be used to mention a user
*/
mentionKeys: PropTypes.arrayOf(PropTypes.string).isRequired,
/*
* The post text to be rendered
*/
message: PropTypes.string.isRequired,
/*
* Any additional text formatting options to be used
*/
options: PropTypes.object,
/*
* The optional post for which this message is being rendered
*/
post: PropTypes.object,
/*
* The root Site URL for the page
*/
siteURL: PropTypes.string.isRequired,
/*
* The current team
*/
team: PropTypes.object.isRequired
};
static defaultProps = {
options: {},
isRHS: false
};
render() {
const options = Object.assign({
emojis: this.props.emojis,
siteURL: this.props.siteURL,
mentionKeys: this.props.mentionKeys,
atMentions: true,
channelNamesMap: this.props.channelNamesMap,
team: this.props.team
}, this.props.options);
if (this.props.post) {
const renderedSystemMessage = renderSystemMessage(this.props.post, options);
if (renderedSystemMessage) {
return <div>{renderedSystemMessage}</div>;
}
}
const htmlFormattedText = TextFormatting.formatText(this.props.message, options);
return <span>{PostUtils.postMessageHtmlToComponent(htmlFormattedText, this.props.isRHS)}</span>;
}
}
......@@ -2,62 +2,20 @@
// See License.txt for license information.
import {connect} from 'react-redux';
import {createSelector} from 'reselect';
import {Preferences} from 'mattermost-redux/constants';
import {getChannelsNameMapInCurrentTeam} from 'mattermost-redux/selectors/entities/channels';
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
import {getTheme, getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser, getCurrentUserMentionKeys, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
import {EmojiMap} from 'stores/emoji_store.jsx';
import {getSiteURL} from 'utils/url.jsx';
import {getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
import PostMessageView from './post_message_view.jsx';
const getChannelNamesMap = createSelector(
(state) => getChannelsNameMapInCurrentTeam(state),
(state, props) => props,
(channelNamesMap, props) => {
if (props && props.channel_mentions) {
return Object.assign({}, props.channel_mentions, channelNamesMap);
}
return channelNamesMap;
}
);
function makeMapStateToProps() {
let emojiMap;
let oldCustomEmoji;
return function mapStateToProps(state, ownProps) {
const newCustomEmoji = getCustomEmojisByName(state);
if (newCustomEmoji !== oldCustomEmoji) {
emojiMap = new EmojiMap(newCustomEmoji);
}
oldCustomEmoji = newCustomEmoji;
const user = getCurrentUser(state);
const channelNamesMap = getChannelNamesMap(state, ownProps.post.props);
return {
...ownProps,
emojis: emojiMap,
enableFormatting: getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', true),
mentionKeys: getCurrentUserMentionKeys(state),
usernameMap: getUsersByUsername(state),
team: getCurrentTeam(state),
siteUrl: getSiteURL(),
theme: getTheme(state),
pluginPostTypes: state.plugins.postTypes,
currentUser: user,
channelNamesMap
};
function mapStateToProps(state) {
return {
enableFormatting: getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', true),
mentionKeys: getCurrentUserMentionKeys(state),
pluginPostTypes: state.plugins.postTypes,
theme: getTheme(state)
};
}
export default connect(makeMapStateToProps)(PostMessageView);
export default connect(mapStateToProps)(PostMessageView);
......@@ -5,13 +5,12 @@ import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import * as PostUtils from 'utils/post_utils.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
import {Posts} from 'mattermost-redux/constants';
import {Posts} from 'mattermost-redux/constants'; // eslint-disable-line import/order
import PostMarkdown from 'components/post_markdown';
import {renderSystemMessage} from './system_message_helpers.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import * as Utils from 'utils/utils.jsx';
export default class PostMessageView extends React.PureComponent {
static propTypes = {
......@@ -21,16 +20,6 @@ export default class PostMessageView extends React.PureComponent {
*/
post: PropTypes.object.isRequired,
/*
* Object using emoji names as keys with custom emojis as the values
*/
emojis: PropTypes.object.isRequired,
/*
* The team the post was made in
*/
team: PropTypes.object.isRequired,
/*
* Set to enable Markdown formatting
*/
......@@ -39,12 +28,7 @@ export default class PostMessageView extends React.PureComponent {
/*
* An array of words that can be used to mention a user
*/
mentionKeys: PropTypes.arrayOf(PropTypes.string),
/*
* The URL that the app is hosted on
*/
siteUrl: PropTypes.string,
mentionKeys: PropTypes.arrayOf(PropTypes.string).isRequired,
/*
* Options specific to text formatting
......@@ -74,22 +58,11 @@ export default class PostMessageView extends React.PureComponent {
/*
* Post type components from plugins
*/
pluginPostTypes: PropTypes.object,
/**
* The logged in user
*/
currentUser: PropTypes.object.isRequired,
/**
* A map of channel names to channel objects
*/
channelNamesMap: PropTypes.object.isRequired
pluginPostTypes: PropTypes.object
};
static defaultProps = {
options: {},
mentionKeys: [],
isRHS: false,
pluginPostTypes: {}
};
......@@ -124,15 +97,12 @@ export default class PostMessageView extends React.PureComponent {
const {
post,
enableFormatting,
options,
pluginPostTypes,
compactDisplay,
isRHS,
theme,
emojis,
siteUrl,
team,
lastPostCount,
channelNamesMap
lastPostCount
} = this.props;
if (post.state === Posts.POST_DELETED) {
......@@ -159,22 +129,6 @@ export default class PostMessageView extends React.PureComponent {
}
}
const mentionKeys = [...this.props.mentionKeys, this.props.currentUser.username];
const options = Object.assign({}, this.props.options, {
emojis,
siteURL: siteUrl,
mentionKeys,
atMentions: true,
channelNamesMap,
team
});
const renderedSystemMessage = renderSystemMessage(post, options);
if (renderedSystemMessage) {
return <div>{renderedSystemMessage}</div>;
}
let postId = null;
if (lastPostCount >= 0) {
postId = Utils.createSafeId('lastPostMessageText' + lastPostCount);
......@@ -186,8 +140,6 @@ export default class PostMessageView extends React.PureComponent {
const visibleMessage = Utils.localizeMessage('post_info.message.visible.compact', ' (Only visible to you)');
message = message.concat(visibleMessage);
}
const htmlFormattedText = TextFormatting.formatText(message, options);
const postMessageComponent = PostUtils.postMessageHtmlToComponent(htmlFormattedText, isRHS);
return (
<div>
......@@ -196,7 +148,13 @@ export default class PostMessageView extends React.PureComponent {
className='post-message__text'
onClick={Utils.handleFormattedTextClick}
>
{postMessageComponent}
<PostMarkdown
message={message}
isRHS={isRHS}
mentionKeys={this.props.mentionKeys}
options={options}
post={post}
/>
</span>
{this.renderEditedIndicator()}
</div>
......
......@@ -7,13 +7,12 @@ import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import UserStore from 'stores/user_store.jsx';
import PostMarkdown from 'components/post_markdown';
import ErrorStore from 'stores/error_store.jsx';
import Constants from 'utils/constants.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import AtMentionProvider from './suggestion/at_mention_provider.jsx';
import ChannelMentionProvider from './suggestion/channel_mention_provider.jsx';
......@@ -271,11 +270,6 @@ export default class Textbox extends React.Component {
</div>
);
const options = {
mentionKeys: UserStore.getCurrentMentionKeys(),
atMentions: true
};
let preview = null;
if (this.state.preview) {
......@@ -285,7 +279,10 @@ export default class Textbox extends React.Component {
className='form-control custom-textarea textbox-preview-area'
style={{display: this.state.preview ? 'block' : 'none'}}
>
{PostUtils.postMessageHtmlToComponent(TextFormatting.formatText(this.props.value, options), this.props.isRHS)}
<PostMarkdown
isRHS={this.props.isRHS}
message={this.props.value}
/>
</div>
);
}
......
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {createSelector} from 'reselect';
import {getCustomEmojisByName} from 'mattermost-redux/selectors/entities/emojis';
import {EmojiMap} from 'stores/emoji_store.jsx';
export const getEmojiMap = createSelector(
getCustomEmojisByName,
(customEmojisByName) => {
return new EmojiMap(customEmojisByName);
}
);
......@@ -57,7 +57,6 @@ exports[`plugins/PostMessageView should match snapshot with extended post type 1
}
enableFormatting={true}
isRHS={false}
mentionKeys={Array []}
options={Object {}}
pluginPostTypes={
Object {
......@@ -68,6 +67,7 @@ exports[`plugins/PostMessageView should match snapshot with extended post type 1
}
post={
Object {
"message": "this is some text",
"type": "testtype",
}
}
......@@ -84,9 +84,9 @@ exports[`plugins/PostMessageView should match snapshot with extended post type 1
>
<PostTypePlugin
isRHS={false}
mentionKeys={Array []}
post={
Object {
"message": "this is some text",
"type": "testtype",
}
}
......@@ -163,11 +163,11 @@ exports[`plugins/PostMessageView should match snapshot with no extended post typ
}
enableFormatting={true}
isRHS={false}
mentionKeys={Array []}
options={Object {}}
pluginPostTypes={Object {}}
post={
Object {
"message": "this is some text",
"type": "testtype",
}
}
......@@ -187,7 +187,51 @@ exports[`plugins/PostMessageView should match snapshot with no extended post typ
className="post-message__text"
id={null}
onClick={[Function]}
/>
>
<Connect(PostMarkdown)
isRHS={false}
message="this is some text"
options={Object {}}
post={
Object {
"message": "this is some text",
"type": "testtype",
}
}
>
<PostMarkdown
channelNamesMap={Object {}}
dispatch={[Function]}
emojis={
EmojiMap {
"customEmojis": Map {},
"customEmojisArray": Array [],
}
}
isRHS={false}
mentionKeys={Array []}
message="this is some text"
options={Object {}}
post={
Object {
"message": "this is some text",
"type": "testtype",
}
}
siteURL="null"
>
<span>
<p
key="0"
>
this is some text
</p>
</span>
</PostMarkdown>
</Connect(PostMarkdown)>
</span>
</div>
</PostMessageView>
</Provider>
......
......@@ -17,7 +17,7 @@ class PostTypePlugin extends React.PureComponent {
}
describe('plugins/PostMessageView', () => {
const post = {type: 'testtype'};
const post = {type: 'testtype', message: 'this is some text'};
const pluginPostTypes = {
testtype: {component: PostTypePlugin}
};
......
......@@ -137,7 +137,7 @@ export function removeCode(text) {
return text.replace(codeBlockPattern, '').replace(inlineCodePattern, ' ');
}
export function postMessageHtmlToComponent(html, isRHS = false) {
export function postMessageHtmlToComponent(html, isRHS) {
const parser = new Parser();
const attrib = 'data-mention';
const processNodeDefinitions = new ProcessNodeDefinitions(React);
......@@ -184,4 +184,4 @@ export function postMessageHtmlToComponent(html, isRHS = false) {
}
];
return parser.parseWithInstructions(html, isValidNode, processingInstructions);
}
\ No newline at end of file
}
......@@ -5614,9 +5614,9 @@ math-expression-evaluator@^1.2.14:
version "1.2.16"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9"
mattermost-redux@1.1.0:
mattermost-redux@mattermost/mattermost-redux#5919d4cb64d91cec783ce91c7f822e96853923c1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mattermost-redux/-/mattermost-redux-1.1.0.tgz#176ea90457a6be4bffe6b0b05cbb2b2ba0afcf77"
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/5919d4cb64d91cec783ce91c7f822e96853923c1"
dependencies:
deep-equal "1.0.1"
form-data "2.3.1"
......