diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js index 874a7364d084..4d066a08f22b 100755 --- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js @@ -33,6 +33,11 @@ const customHTMLElementModels = { }), comment: defaultHTMLElementModels.div.extend({ tagName: 'comment', + mixedUAStyles: {whiteSpace: 'pre'}, + }), + 'email-comment': defaultHTMLElementModels.div.extend({ + tagName: 'email-comment', + mixedUAStyles: {whiteSpace: 'normal'}, }), }; diff --git a/src/components/HTMLEngineProvider/htmlEngineUtils.js b/src/components/HTMLEngineProvider/htmlEngineUtils.js index dc678b99d601..71a5e9267835 100644 --- a/src/components/HTMLEngineProvider/htmlEngineUtils.js +++ b/src/components/HTMLEngineProvider/htmlEngineUtils.js @@ -17,6 +17,16 @@ function computeEmbeddedMaxWidth(tagName, contentWidth) { return contentWidth; } +/** + * Check if tagName is equal to any of our custom tags wrapping chat comments. + * + * @param {string} tagName + * @returns {Boolean} + */ +function isCommentTag(tagName) { + return tagName === 'email-comment' || tagName === 'comment'; +} + /** * Check if there is an ancestor node with name 'comment'. * Finding node with name 'comment' flags that we are rendering a comment. @@ -26,7 +36,7 @@ function computeEmbeddedMaxWidth(tagName, contentWidth) { function isInsideComment(tnode) { let currentNode = tnode; while (currentNode.parent) { - if (currentNode.domNode.name === 'comment') { + if (isCommentTag(currentNode.domNode.name)) { return true; } currentNode = currentNode.parent; @@ -37,4 +47,5 @@ function isInsideComment(tnode) { export { computeEmbeddedMaxWidth, isInsideComment, + isCommentTag, }; diff --git a/src/libs/SelectionScraper/index.js b/src/libs/SelectionScraper/index.js index 363367072631..7f0a9d69959d 100644 --- a/src/libs/SelectionScraper/index.js +++ b/src/libs/SelectionScraper/index.js @@ -4,6 +4,7 @@ import {parseDocument} from 'htmlparser2'; import {Element} from 'domhandler'; import _ from 'underscore'; import Str from 'expensify-common/lib/str'; +import {isCommentTag} from '../../components/HTMLEngineProvider/htmlEngineUtils'; const elementsWillBeSkipped = ['html', 'body']; const tagAttribute = 'data-testid'; @@ -103,7 +104,7 @@ const replaceNodes = (dom) => { } // Adding a new line after each comment here, because adding after each range is not working for chrome. - if (dom.attribs[tagAttribute] === 'comment') { + if (isCommentTag(dom.attribs[tagAttribute])) { dom.children.push(new Element('br', {})); } } diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index afab5787fb75..964142ca5b95 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -44,6 +44,9 @@ const propTypes = { /** Does this fragment belong to a reportAction that has not yet loaded? */ loading: PropTypes.bool, + /** The reportAction's source */ + source: PropTypes.oneOf(['Chronos', 'email', 'ios', 'android', 'web', 'email', '']), + /** Should this fragment be contained in a single line? */ isSingleLine: PropTypes.bool, @@ -64,6 +67,7 @@ const defaultProps = { loading: false, isSingleLine: false, tooltipText: '', + source: '', }; const ReportActionItemFragment = (props) => { @@ -86,6 +90,7 @@ const ReportActionItemFragment = (props) => { ) ); } + let {html, text} = props.fragment; // If the only difference between fragment.text and fragment.html is
tags // we replace them with line breaks and render it as text, not as html. @@ -93,32 +98,38 @@ const ReportActionItemFragment = (props) => { const differByLineBreaksOnly = Str.replaceAll(props.fragment.html, '
', ' ') === props.fragment.text; if (differByLineBreaksOnly) { const textWithLineBreaks = Str.replaceAll(props.fragment.html, '
', '\n'); - // eslint-disable-next-line no-param-reassign - props.fragment = {...props.fragment, text: textWithLineBreaks, html: textWithLineBreaks}; + html = textWithLineBreaks; + text = textWithLineBreaks; } // Only render HTML if we have html in the fragment - return props.fragment.html !== props.fragment.text - ? ( + if (html !== text) { + const editedTag = props.fragment.isEdited ? '' : ''; + const htmlContent = html + editedTag; + return ( ${props.fragment.html + (props.fragment.isEdited ? '' : '')}`} + html={props.source === 'email' + ? `${htmlContent}` + : `${htmlContent}`} /> - ) : ( - - {Str.htmlDecode(props.fragment.text)} - {props.fragment.isEdited && ( - - {` ${props.translate('reportActionCompose.edited')}`} - - )} - ); + } + return ( + + {Str.htmlDecode(text)} + {props.fragment.isEdited && ( + + {` ${props.translate('reportActionCompose.edited')}`} + + )} + + ); } case 'TEXT': return ( diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index fd6bb82fa023..18d4b2306807 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; +import lodashGet from 'lodash/get'; import styles from '../../../styles/styles'; import ReportActionItemFragment from './ReportActionItemFragment'; import reportActionPropTypes from './reportActionPropTypes'; @@ -32,6 +33,7 @@ const ReportActionItemMessage = (props) => { fragment={fragment} isAttachment={props.action.isAttachment} attachmentInfo={props.action.attachmentInfo} + source={lodashGet(props.action, 'originalMessage.source')} loading={props.action.isLoading} /> ))} diff --git a/src/styles/styles.js b/src/styles/styles.js index 482a70f56ca3..a654974d6f78 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -135,7 +135,6 @@ const webViewStyles = { fontSize: variables.fontSizeNormal, fontFamily: fontFamily.GTA, flex: 1, - whiteSpace: 'pre', }, };