fix(inline-attachments): Precompute sizes for better inline attachment loading

Summary: test case and fixes

Test Plan: Run new test!

Reviewers: evan

Reviewed By: evan

Differential Revision: https://review.inboxapp.com/D1309
This commit is contained in:
Ben Gotow 2015-03-18 13:54:34 -07:00
parent d283cb432b
commit b61863d332
3 changed files with 43 additions and 4 deletions

View file

@ -7,6 +7,9 @@ MessageTimestamp = require "./message-timestamp.cjsx"
{RetinaImg} = require 'ui-components'
Autolinker = require 'autolinker'
TransparentPixel = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII="
MessageBodyWidth = 740
module.exports =
MessageItem = React.createClass
displayName: 'MessageItem'
@ -143,16 +146,36 @@ MessageItem = React.createClass
# Apply the autolinker pass to make emails and links clickable
body = Autolinker.link(body, {twitter: false})
# Find cid:// references and replace them with the paths to downloaded files
# Find inline images and give them a calculated CSS height based on
# html width and height, when available. This means nothing changes size
# as the image is loaded, and we can estimate final height correctly.
# Note that MessageBodyWidth must be updated if the UI is changed!
cidRegex = /src=['"]cid:([^'"]*)['"]/g
while (result = cidRegex.exec(body)) isnt null
imgstart = body.lastIndexOf('<', result.index)
imgend = body.indexOf('/>', result.index)
if imgstart != -1 and imgend > imgstart
imgtag = body.substr(imgstart, imgend - imgstart)
width = imgtag.match(/width[ ]?=[ ]?['"]?(\d*)['"]?/)?[1]
height = imgtag.match(/height[ ]?=[ ]?['"]?(\d*)['"]?/)?[1]
if width and height
scale = Math.min(1, MessageBodyWidth / width)
style = " style=\"height:#{height * scale}px;\" "
body = body.substr(0, imgend) + style + body.substr(imgend)
# Replace cid:// references with the paths to downloaded files
for file in @props.message.files
continue if _.find @state.downloads, (d) -> d.fileId is file.id
cidLink = "cid:#{file.contentId}"
fileLink = "#{FileDownloadStore.pathForFile(file)}"
body = body.replace(cidLink, fileLink)
# Remove any remaining cid:// references - we will not display them since they'll
# throw "unknown ERR_UNKNOWN_URL_SCHEME"
body = body.replace(/src=['"]cid:[^'"]*['"]/g, '')
# 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(/src=['"]cid:[^'"]*['"]/g, "src=\"#{TransparentPixel}\"")
body

View file

@ -204,6 +204,20 @@ describe "MessageItem", ->
body = @component._formatBody()
expect(body.indexOf('cid')).toEqual(-1)
it "should give images a fixed height when height and width are set as html attributes", ->
@message.body = """
<img src=\"cid:#{file_inline.contentId}\"/>
<img src=\"cid:#{file_inline.contentId}\" width="50"/>
<img src=\"cid:#{file_inline.contentId}\" width="50" height="40"/>
<img src=\"cid:#{file_inline.contentId}\" width="1000" height="800"/>
"""
@createComponent()
body = @component._formatBody()
expect(body).toEqual """<img src="/fake/path-inline.png"/>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII=" width="50"/>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII=" width="50" height="40" style="height:40px;" />
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII=" width="1000" height="800" style="height:592px;" />
"""
it "should replace cid://<file.contentId> with the FileDownloadStore's path for the file", ->
body = @component._formatBody()
expect(body.indexOf('alt="A" src="/fake/path-inline.png"')).toEqual(@message.body.indexOf('alt="A"'))

View file

@ -42,6 +42,8 @@ ContainerView = React.createClass
query = node.getUrl().split('?')[1]
token = querystring.decode(query)
OnboardingActions.finishedConnect(token)
if node.getUrl().indexOf('cancelled') != -1
OnboardingActions.moveToPreviousPage()
render: ->
<ReactCSSTransitionGroup transitionName="page">