You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChatMessage.js 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // @flow
  2. import React from 'react';
  3. import { toArray } from 'react-emoji-render';
  4. import { translate } from '../../../base/i18n';
  5. import { Linkify } from '../../../base/react';
  6. import { MESSAGE_TYPE_LOCAL } from '../../constants';
  7. import AbstractChatMessage, {
  8. type Props
  9. } from '../AbstractChatMessage';
  10. import PrivateMessageButton from '../PrivateMessageButton';
  11. /**
  12. * Renders a single chat message.
  13. */
  14. class ChatMessage extends AbstractChatMessage<Props> {
  15. /**
  16. * Implements React's {@link Component#render()}.
  17. *
  18. * @inheritdoc
  19. * @returns {ReactElement}
  20. */
  21. render() {
  22. const { message, t } = this.props;
  23. const processedMessage = [];
  24. const txt = this._getMessageText();
  25. // Tokenize the text in order to avoid emoji substitution for URLs.
  26. const tokens = txt.split(' ');
  27. // Content is an array of text and emoji components
  28. const content = [];
  29. for (const token of tokens) {
  30. if (token.includes('://')) {
  31. // It contains a link, bypass the emojification.
  32. content.push(token);
  33. } else {
  34. content.push(...toArray(token, { className: 'smiley' }));
  35. }
  36. content.push(' ');
  37. }
  38. content.forEach(i => {
  39. if (typeof i === 'string' && i !== ' ') {
  40. processedMessage.push(<Linkify key = { i }>{ i }</Linkify>);
  41. } else {
  42. processedMessage.push(i);
  43. }
  44. });
  45. return (
  46. <div
  47. className = 'chatmessage-wrapper'
  48. tabIndex = { -1 }>
  49. <div className = { `chatmessage ${message.privateMessage ? 'privatemessage' : ''}` }>
  50. <div className = 'replywrapper'>
  51. <div className = 'messagecontent'>
  52. { this.props.showDisplayName && this._renderDisplayName() }
  53. <div className = 'usermessage'>
  54. <span className = 'sr-only'>
  55. { this.props.message.displayName === this.props.message.recipient
  56. ? t('chat.messageAccessibleTitleMe')
  57. : t('chat.messageAccessibleTitle',
  58. { user: this.props.message.displayName }) }
  59. </span>
  60. { processedMessage }
  61. </div>
  62. { message.privateMessage && this._renderPrivateNotice() }
  63. </div>
  64. { message.privateMessage && message.messageType !== MESSAGE_TYPE_LOCAL
  65. && (
  66. <div className = 'messageactions'>
  67. <PrivateMessageButton
  68. participantID = { message.id }
  69. reply = { true }
  70. showLabel = { false } />
  71. </div>
  72. ) }
  73. </div>
  74. </div>
  75. { this.props.showTimestamp && this._renderTimestamp() }
  76. </div>
  77. );
  78. }
  79. _getFormattedTimestamp: () => string;
  80. _getMessageText: () => string;
  81. _getPrivateNoticeMessage: () => string;
  82. /**
  83. * Renders the display name of the sender.
  84. *
  85. * @returns {React$Element<*>}
  86. */
  87. _renderDisplayName() {
  88. return (
  89. <div
  90. aria-hidden = { true }
  91. className = 'display-name'>
  92. { this.props.message.displayName }
  93. </div>
  94. );
  95. }
  96. /**
  97. * Renders the message privacy notice.
  98. *
  99. * @returns {React$Element<*>}
  100. */
  101. _renderPrivateNotice() {
  102. return (
  103. <div className = 'privatemessagenotice'>
  104. { this._getPrivateNoticeMessage() }
  105. </div>
  106. );
  107. }
  108. /**
  109. * Renders the time at which the message was sent.
  110. *
  111. * @returns {React$Element<*>}
  112. */
  113. _renderTimestamp() {
  114. return (
  115. <div className = 'timestamp'>
  116. { this._getFormattedTimestamp() }
  117. </div>
  118. );
  119. }
  120. }
  121. export default translate(ChatMessage);