// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {Parser, ProcessNodeDefinitions} from 'html-to-react';
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import AtMention from 'components/at_mention';
import MarkdownImage from 'components/markdown_image';
import store from 'stores/redux_store.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as Utils from 'utils/utils.jsx';
import {getChannelsNameMapInCurrentTeam} from 'mattermost-redux/selectors/entities/channels';
import {Posts} from 'mattermost-redux/constants';
import {renderSystemMessage} from './system_message_helpers.jsx';
export default class PostMessageView extends React.PureComponent {
static propTypes = {
/*
* The post to render the message for
*/
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
*/
enableFormatting: PropTypes.bool,
/*
* 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,
/*
* Options specific to text formatting
*/
options: PropTypes.object,
/*
* Post identifiers for selenium tests
*/
lastPostCount: PropTypes.number,
/**
* Set to render post body compactly
*/
compactDisplay: PropTypes.bool,
/**
* Flags if the post_message_view is for the RHS (Reply).
*/
isRHS: PropTypes.bool,
/**
* Flags if the post_message_view is for the RHS (Reply).
*/
hasMention: PropTypes.bool
};
static defaultProps = {
options: {},
mentionKeys: [],
isRHS: false,
hasMention: false
};
renderDeletedPost() {
return (
);
}
renderEditedIndicator() {
if (!PostUtils.isEdited(this.props.post)) {
return null;
}
return (
);
}
postMessageHtmlToComponent(html) {
const parser = new Parser();
const attrib = 'data-mention';
const processNodeDefinitions = new ProcessNodeDefinitions(React);
function isValidNode() {
return true;
}
const processingInstructions = [
{
replaceChildren: true,
shouldProcessNode: (node) => node.attribs && node.attribs[attrib],
processNode: (node) => {
const mentionName = node.attribs[attrib];
return (
);
}
},
{
shouldProcessNode: (node) => node.type === 'tag' && node.name === 'img',
processNode: (node) => {
const {
class: className,
...attribs
} = node.attribs;
return (
);
}
},
{
shouldProcessNode: () => true,
processNode: processNodeDefinitions.processDefaultNode
}
];
return parser.parseWithInstructions(html, isValidNode, processingInstructions);
}
render() {
if (this.props.post.state === Posts.POST_DELETED) {
return this.renderDeletedPost();
}
if (!this.props.enableFormatting) {
return {this.props.post.message};
}
const options = Object.assign({}, this.props.options, {
emojis: this.props.emojis,
siteURL: this.props.siteUrl,
mentionKeys: this.props.mentionKeys,
atMentions: true,
channelNamesMap: getChannelsNameMapInCurrentTeam(store.getState()),
team: this.props.team
});
const renderedSystemMessage = renderSystemMessage(this.props.post, options);
if (renderedSystemMessage) {
return {renderedSystemMessage}
;
}
let postId = null;
if (this.props.lastPostCount >= 0) {
postId = Utils.createSafeId('lastPostMessageText' + this.props.lastPostCount);
}
let message = this.props.post.message;
const isEphemeral = Utils.isPostEphemeral(this.props.post);
if (this.props.compactDisplay && isEphemeral) {
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 = this.postMessageHtmlToComponent(htmlFormattedText);
return (
{postMessageComponent}
{this.renderEditedIndicator()}
);
}
}