mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-11 18:32:20 +08:00
aa7ef91b0b
Summary: When you have your "Download attachments for new mail" setting set to "manually", inline images always appear broken with no explanation. This patch listens for the image load to fail and displays a button which queues the fetchFile task on click. This seemed like the best approach because it doesn't slow down the loading of the message with more fstats / lookups. (Seeing if the file has already been downloaded is an async operation) Test Plan: No specs atm Reviewers: evan, juan Reviewed By: juan Differential Revision: https://phab.nylas.com/D3313
132 lines
4.7 KiB
CoffeeScript
132 lines
4.7 KiB
CoffeeScript
React = require 'react'
|
|
_ = require 'underscore'
|
|
EmailFrame = require('./email-frame').default
|
|
{encodedAttributeForFile} = require('./inline-download-prompts')
|
|
{
|
|
DraftHelpers,
|
|
CanvasUtils,
|
|
NylasAPI,
|
|
MessageUtils,
|
|
MessageBodyProcessor,
|
|
QuotedHTMLTransformer,
|
|
FileDownloadStore
|
|
} = require 'nylas-exports'
|
|
{InjectedComponentSet, RetinaImg} = require 'nylas-component-kit'
|
|
|
|
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) ->
|
|
@_mounted = false
|
|
@state =
|
|
showQuotedText: DraftHelpers.isForwardedMessage(@props.message)
|
|
processedBody: null
|
|
error: null
|
|
|
|
componentWillMount: =>
|
|
@_unsub = MessageBodyProcessor.subscribe @props.message, (processedBody) =>
|
|
@setState({processedBody})
|
|
|
|
componentDidMount: =>
|
|
@_mounted = true
|
|
@_onFetchBody() if not _.isString(@props.message.body)
|
|
|
|
componentWillReceiveProps: (nextProps) ->
|
|
if nextProps.message.id isnt @props.message.id
|
|
@_unsub?()
|
|
@_unsub = MessageBodyProcessor.subscribe nextProps.message, (processedBody) =>
|
|
@setState({processedBody})
|
|
|
|
componentWillUnmount: =>
|
|
@_mounted = false
|
|
@_unsub?()
|
|
|
|
render: =>
|
|
<span>
|
|
<InjectedComponentSet
|
|
matching={role: "message:BodyHeader"}
|
|
exposedProps={message: @props.message}
|
|
direction="column"
|
|
style={width:'100%'}/>
|
|
{@_renderBody()}
|
|
{@_renderQuotedTextControl()}
|
|
</span>
|
|
|
|
_renderBody: =>
|
|
if _.isString(@props.message.body) and _.isString(@state.processedBody)
|
|
<EmailFrame
|
|
showQuotedText={@state.showQuotedText}
|
|
content={@_mergeBodyWithFiles(@state.processedBody)}
|
|
message={@props.message}
|
|
/>
|
|
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>
|
|
|
|
_renderQuotedTextControl: =>
|
|
return null unless QuotedHTMLTransformer.hasQuotedHTML(@props.message.body)
|
|
<a className="quoted-text-control" onClick={@_toggleQuotedText}>
|
|
<span className="dots">•••</span>
|
|
</a>
|
|
|
|
_toggleQuotedText: =>
|
|
@setState
|
|
showQuotedText: !@state.showQuotedText
|
|
|
|
_onFetchBody: =>
|
|
NylasAPI.makeRequest
|
|
path: "/messages/#{@props.message.id}"
|
|
accountId: @props.message.accountId
|
|
returnsModel: true
|
|
.then =>
|
|
return unless @_mounted
|
|
@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 unless @_mounted
|
|
@setState({error})
|
|
|
|
_mergeBodyWithFiles: (body) =>
|
|
# Replace cid: references with the paths to downloaded files
|
|
for file in @props.message.files
|
|
download = @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.
|
|
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) ->
|
|
dataUri = CanvasUtils.dataURIForLoadedPercent(download.percent)
|
|
"#{dataUri}#{quoteCharacter} style=#{quoteCharacter} object-position: 50% 50%; object-fit: none; "
|
|
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")
|
|
body = body.replace cidRegexp, (text, quoteCharacter) ->
|
|
"file://#{FileDownloadStore.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.
|
|
body = body.replace(MessageUtils.cidRegex, "src=\"#{TransparentPixel}\"")
|
|
|
|
return body
|
|
|
|
module.exports = MessageItemBody
|