import React from 'react' import { DraftHelpers, MessageUtils, MessageBodyProcessor, QuotedHTMLTransformer, AttachmentStore, } from 'nylas-exports'; import { InjectedComponentSet, RetinaImg, } from 'nylas-component-kit'; import EmailFrame from './email-frame'; import {encodedAttributeForFile} from './inline-image-listeners'; const TransparentPixel = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII=" export default class MessageItemBody extends React.Component { static displayName = 'MessageItemBody'; static propTypes = { message: React.PropTypes.object.isRequired, downloads: React.PropTypes.object.isRequired, }; constructor(props, context) { super(props, context); this._mounted = false; this.state = { showQuotedText: DraftHelpers.isForwardedMessage(this.props.message), processedBody: null, }; } componentWillMount() { this._unsub = MessageBodyProcessor.subscribe(this.props.message, (processedBody) => this.setState({processedBody}) ); } componentDidMount() { this._mounted = true; } componentWillReceiveProps(nextProps) { if (nextProps.message.id !== this.props.message.id) { if (this._unsub) { this._unsub() } this._unsub = MessageBodyProcessor.subscribe(nextProps.message, (processedBody) => this.setState({processedBody}) ); } } componentWillUnmount() { this._mounted = false; if (this._unsub) { this._unsub() } } _onToggleQuotedText = () => { this.setState({ showQuotedText: !this.state.showQuotedText, }); } _mergeBodyWithFiles(body) { let merged = body; // Replace cid: references with the paths to downloaded files for (const file of this.props.message.files) { const download = this.props.downloads[file.id]; // Note: I don't like doing this with RegExp before the body is inserted into // the DOM, but we want to avoid "could not load cid://" in the console. if (download && download.state !== 'finished') { const inlineImgRegexp = new RegExp(`<\\s*img.*src=['"]cid:${file.contentId}['"][^>]*>`, 'gi') // Render a spinner merged = merged.replace(inlineImgRegexp, () => 'spinner.gif' ); } else { // Render the completed download. We include data-nylas-file so that if the image fails // to load, we can parse the file out and call `Actions.fetchFile` to retrieve it. // (Necessary when attachment download mode is set to "manual") const cidRegexp = new RegExp(`cid:${file.contentId}(['"])`, 'gi') merged = merged.replace(cidRegexp, (text, quoteCharacter) => `file://${AttachmentStore.pathForFile(file)}${quoteCharacter} data-nylas-file="${encodedAttributeForFile(file)}" ` ); } } // Replace remaining cid: references - we will not display them since they'll // throw "unknown ERR_UNKNOWN_URL_SCHEME". Show a transparent pixel so that there's // no "missing image" region shown, just a space. merged = merged.replace(MessageUtils.cidRegex, `src="${TransparentPixel}"`) return merged; } _renderBody() { const {message} = this.props; const {showQuotedText, processedBody} = this.state; if (typeof message.body === "string" && typeof processedBody === "string") { return ( ); } return (
); } _renderQuotedTextControl() { if (!QuotedHTMLTransformer.hasQuotedHTML(this.props.message.body)) { return null; } return ( ••• ); } render() { return ( {this._renderBody()} {this._renderQuotedTextControl()} ); } }