2015-11-07 07:53:21 +08:00
|
|
|
React = require 'react'
|
|
|
|
_ = require 'underscore'
|
|
|
|
EmailFrame = require './email-frame'
|
|
|
|
{Utils,
|
2016-03-10 10:01:13 +08:00
|
|
|
NylasAPI,
|
2015-11-07 07:53:21 +08:00
|
|
|
MessageUtils,
|
|
|
|
MessageBodyProcessor,
|
2015-12-08 07:34:03 +08:00
|
|
|
QuotedHTMLTransformer,
|
2015-11-07 07:53:21 +08:00
|
|
|
FileDownloadStore} = require 'nylas-exports'
|
2016-03-10 10:01:13 +08:00
|
|
|
{InjectedComponentSet, RetinaImg} = require 'nylas-component-kit'
|
2015-11-07 07:53:21 +08:00
|
|
|
|
|
|
|
TransparentPixel = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII="
|
|
|
|
|
|
|
|
class MessageItemBody extends React.Component
|
|
|
|
@displayName: 'MessageItemBody'
|
|
|
|
@propTypes:
|
|
|
|
message: React.PropTypes.object.isRequired
|
|
|
|
downloads: React.PropTypes.object.isRequired
|
|
|
|
|
|
|
|
constructor: (@props) ->
|
2016-03-10 10:01:13 +08:00
|
|
|
@_unmounted = false
|
2015-11-07 07:53:21 +08:00
|
|
|
@state =
|
|
|
|
showQuotedText: Utils.isForwardedMessage(@props.message)
|
2016-03-10 10:01:13 +08:00
|
|
|
processedBody: null
|
|
|
|
error: null
|
2015-11-07 07:53:21 +08:00
|
|
|
|
|
|
|
componentWillMount: =>
|
2016-03-10 10:01:13 +08:00
|
|
|
@_unsub = MessageBodyProcessor.subscribe(@props.message, @_onBodyProcessed)
|
|
|
|
|
|
|
|
componentDidMount: =>
|
|
|
|
@_onFetchBody() if not _.isString(@props.message.body)
|
2015-11-07 07:53:21 +08:00
|
|
|
|
2016-03-09 05:06:54 +08:00
|
|
|
componentWillReceiveProps: (nextProps) ->
|
|
|
|
if nextProps.message.id isnt @props.message.id
|
|
|
|
@_unsub?()
|
2016-03-10 10:01:13 +08:00
|
|
|
@_unsub = MessageBodyProcessor.subscribe(nextProps.message, @_onBodyProcessed)
|
2015-11-19 04:32:07 +08:00
|
|
|
|
2015-11-07 07:53:21 +08:00
|
|
|
componentWillUnmount: =>
|
2016-03-10 10:01:13 +08:00
|
|
|
@_unmounted = true
|
2015-11-07 07:53:21 +08:00
|
|
|
@_unsub?()
|
|
|
|
|
|
|
|
render: =>
|
|
|
|
<span>
|
|
|
|
<InjectedComponentSet
|
|
|
|
matching={role: "message:BodyHeader"}
|
|
|
|
exposedProps={message: @props.message}
|
|
|
|
direction="column"
|
|
|
|
style={width:'100%'}/>
|
|
|
|
{@_renderBody()}
|
|
|
|
{@_renderQuotedTextControl()}
|
|
|
|
</span>
|
|
|
|
|
|
|
|
_renderBody: =>
|
2016-03-11 08:13:17 +08:00
|
|
|
if _.isString(@props.message.body) and _.isString(@state.processedBody)
|
2016-03-10 10:01:13 +08:00
|
|
|
<EmailFrame showQuotedText={@state.showQuotedText} content={@state.processedBody}/>
|
|
|
|
else if @state.error
|
|
|
|
<div className="message-body-error">
|
|
|
|
Sorry, this message could not be loaded. (Status code {@state.error.statusCode})
|
|
|
|
<a onClick={@_onFetchBody}>Try Again</a>
|
|
|
|
</div>
|
|
|
|
else
|
|
|
|
<div className="message-body-loading">
|
|
|
|
<RetinaImg
|
|
|
|
name="inline-loading-spinner.gif"
|
|
|
|
mode={RetinaImg.Mode.ContentDark}
|
|
|
|
style={{width: 14, height: 14}}/>
|
|
|
|
</div>
|
2015-11-07 07:53:21 +08:00
|
|
|
|
|
|
|
_renderQuotedTextControl: =>
|
2015-12-08 07:34:03 +08:00
|
|
|
return null unless QuotedHTMLTransformer.hasQuotedHTML(@props.message.body)
|
2015-11-07 07:53:21 +08:00
|
|
|
text = if @state.showQuotedText then "Hide" else "Show"
|
|
|
|
<a className="quoted-text-control" onClick={@_toggleQuotedText}>
|
|
|
|
<span className="dots">•••</span>{text} previous
|
|
|
|
</a>
|
|
|
|
|
|
|
|
_toggleQuotedText: =>
|
|
|
|
@setState
|
|
|
|
showQuotedText: !@state.showQuotedText
|
|
|
|
|
2016-03-10 10:01:13 +08:00
|
|
|
_onFetchBody: =>
|
|
|
|
NylasAPI.makeRequest
|
|
|
|
path: "/messages/#{@props.message.id}"
|
|
|
|
accountId: @props.message.accountId
|
|
|
|
returnsModel: true
|
|
|
|
.then =>
|
|
|
|
return if @_unmounted
|
|
|
|
@setState({error: null})
|
|
|
|
# message will be put into the database and the MessageBodyProcessor
|
|
|
|
# will provide us with the new body once it's been processed.
|
|
|
|
.catch (error) =>
|
|
|
|
return if @_unmounted
|
|
|
|
@setState({error})
|
|
|
|
|
|
|
|
_onBodyProcessed: (body) =>
|
2015-12-08 07:00:20 +08:00
|
|
|
downloadingSpinnerPath = Utils.imageNamed('inline-loading-spinner.gif')
|
|
|
|
|
2015-11-07 07:53:21 +08:00
|
|
|
# Replace cid:// references with the paths to downloaded files
|
|
|
|
for file in @props.message.files
|
2015-12-08 07:00:20 +08:00
|
|
|
download = @props.downloads[file.id]
|
|
|
|
cidRegexp = new RegExp("cid:#{file.contentId}(['\"]+)", 'gi')
|
|
|
|
|
|
|
|
if download and download.state isnt 'finished'
|
|
|
|
# Render a spinner and inject a `style` tag that injects object-position / object-fit
|
|
|
|
body = body.replace cidRegexp, (text, quoteCharacter) ->
|
|
|
|
"#{downloadingSpinnerPath}#{quoteCharacter} style=#{quoteCharacter} object-position: 50% 50%; object-fit: none; "
|
|
|
|
else
|
|
|
|
# Render the completed download
|
|
|
|
body = body.replace cidRegexp, (text, quoteCharacter) ->
|
|
|
|
"#{FileDownloadStore.pathForFile(file)}#{quoteCharacter}"
|
2015-11-07 07:53:21 +08:00
|
|
|
|
|
|
|
# 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.
|
|
|
|
body = body.replace(MessageUtils.cidRegex, "src=\"#{TransparentPixel}\"")
|
|
|
|
|
|
|
|
@setState
|
|
|
|
processedBody: body
|
|
|
|
|
|
|
|
module.exports = MessageItemBody
|