mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-03-30 09:02:31 +08:00
fix(inline): Use vw
for max-width, use DOM rather than regex
This commit is contained in:
parent
78681f6ed1
commit
3d8133ff8d
4 changed files with 60 additions and 52 deletions
internal_packages/message-list
src/flux/stores
51
internal_packages/message-list/lib/autoscale-images.es6
Normal file
51
internal_packages/message-list/lib/autoscale-images.es6
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
function _getDimension(node, dim) {
|
||||
const raw = node.style[dim] || node[dim];
|
||||
if (!raw) {
|
||||
return [null, ''];
|
||||
}
|
||||
const valueRegexp = /(\d*)(.*)/;
|
||||
const match = valueRegexp.exec(raw);
|
||||
if (!match) {
|
||||
return [null, ''];
|
||||
}
|
||||
|
||||
const value = match[1];
|
||||
const units = match[2] || 'px';
|
||||
return [value / 1, units];
|
||||
}
|
||||
|
||||
function _runOnImageNode(node) {
|
||||
const [width, widthUnits] = _getDimension(node, 'width');
|
||||
const [height, heightUnits] = _getDimension(node, 'height');
|
||||
|
||||
if (node.style.maxWidth || node.style.maxHeight) {
|
||||
return;
|
||||
}
|
||||
// VW is like %, but always basd on the iframe width, regardless of whether
|
||||
// a container is position: relative.
|
||||
// https://web-design-weekly.com/2014/11/18/viewport-units-vw-vh-vmin-vmax/
|
||||
if (width && height && (widthUnits === heightUnits)) {
|
||||
node.style.maxWidth = '100vw';
|
||||
node.style.maxHeight = `${100 * height / width}vw`;
|
||||
} else if (width && !height) {
|
||||
node.style.maxWidth = '100vw';
|
||||
}
|
||||
}
|
||||
|
||||
export function autoscaleImages(doc) {
|
||||
// Traverse the new DOM tree and make things that look like links clickable,
|
||||
// and ensure anything with an href has a title attribute.
|
||||
const imgTagWalker = document.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, {
|
||||
acceptNode: (node) => {
|
||||
if (node.nodeName === 'IMG') {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
},
|
||||
});
|
||||
|
||||
while (imgTagWalker.nextNode()) {
|
||||
_runOnImageNode(imgTagWalker.currentNode);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import _ from "underscore";
|
|||
import {EventedIFrame} from 'nylas-component-kit';
|
||||
import {Utils, QuotedHTMLTransformer} from 'nylas-exports';
|
||||
import {autolink} from './autolinker';
|
||||
import {autoscaleImages} from './autoscale-images';
|
||||
import EmailFrameStylesStore from './email-frame-styles-store';
|
||||
|
||||
export default class EmailFrame extends React.Component {
|
||||
|
@ -66,16 +67,16 @@ export default class EmailFrame extends React.Component {
|
|||
doc.close();
|
||||
|
||||
autolink(doc, {async: true});
|
||||
autoscaleImages(doc);
|
||||
|
||||
// Notify the EventedIFrame that we've replaced it's document (with `open`)
|
||||
// so it can attach event listeners again.
|
||||
this.refs.iframe.documentWasReplaced();
|
||||
this.refs.iframe.didReplaceDocument();
|
||||
this._onMustRecalculateFrameHeight();
|
||||
}
|
||||
|
||||
_onMustRecalculateFrameHeight = () => {
|
||||
const iframeNode = ReactDOM.findDOMNode(this.refs.iframe);
|
||||
iframeNode.height = `0px`;
|
||||
this.refs.iframe.setHeightQuietly(0);
|
||||
this._lastComputedHeight = 0;
|
||||
this._setFrameHeight();
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ export default class EmailFrame extends React.Component {
|
|||
ref="iframe"
|
||||
seamless="seamless"
|
||||
searchable
|
||||
onResize={this._onResize}
|
||||
onResize={this._onMustRecalculateFrameHeight}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
proxyquire = require 'proxyquire'
|
||||
React = require "react"
|
||||
ReactDOM = require "react-dom"
|
||||
ReactTestUtils = require('react-addons-test-utils')
|
||||
|
||||
{Contact,
|
||||
|
@ -143,34 +144,17 @@ describe "MessageItem", ->
|
|||
@createComponent()
|
||||
|
||||
it "should never leave src=cid:// in the message body", ->
|
||||
body = @component.state.processedBody
|
||||
body = ReactTestUtils.findRenderedComponentWithType(@component, EmailFrameStub).props.content
|
||||
expect(body.indexOf('cid')).toEqual(-1)
|
||||
|
||||
it "should replace cid://<file.contentId> with the FileDownloadStore's path for the file", ->
|
||||
body = @component.state.processedBody
|
||||
body = ReactTestUtils.findRenderedComponentWithType(@component, EmailFrameStub).props.content
|
||||
expect(body.indexOf('alt="A" src="/fake/path-inline.png"')).toEqual(@message.body.indexOf('alt="A"'))
|
||||
|
||||
it "should not replace cid://<file.contentId> with the FileDownloadStore's path if the download is in progress", ->
|
||||
body = @component.state.processedBody
|
||||
body = ReactTestUtils.findRenderedComponentWithType(@component, EmailFrameStub).props.content
|
||||
expect(body.indexOf('/fake/path-downloading.png')).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}'/>
|
||||
<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.state.processedBody
|
||||
expect(body).toEqual """<img src="/fake/path-inline.png"/>
|
||||
<img src='/fake/path-inline.png'/>
|
||||
<img src="/fake/path-inline.png" width="50"/>
|
||||
<img src="/fake/path-inline.png" width="50" height="40" style="height:40px;" />
|
||||
<img src="/fake/path-inline.png" width="1000" height="800" style="height:592px;" />
|
||||
"""
|
||||
|
||||
describe "showQuotedText", ->
|
||||
it "should be initialized to false", ->
|
||||
@createComponent()
|
||||
|
|
|
@ -4,8 +4,6 @@ import MessageUtils from '../models/message-utils';
|
|||
import MessageStore from './message-store';
|
||||
import DatabaseStore from './database-store';
|
||||
|
||||
const MessageBodyWidth = 740;
|
||||
|
||||
class MessageBodyProcessor {
|
||||
constructor() {
|
||||
this._subscriptions = [];
|
||||
|
@ -122,32 +120,6 @@ class MessageBodyProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
// 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!
|
||||
let result = MessageUtils.cidRegex.exec(body);
|
||||
|
||||
while (result !== null) {
|
||||
const imgstart = body.lastIndexOf('<', result.index);
|
||||
const imgend = body.indexOf('/>', result.index);
|
||||
|
||||
if ((imgstart !== -1) && (imgend > imgstart)) {
|
||||
const imgtag = body.substr(imgstart, imgend - imgstart);
|
||||
const widthMatch = imgtag.match(/width[ ]?=[ ]?['"]?(\d*)['"]?/);
|
||||
const width = widthMatch ? widthMatch[1] : null;
|
||||
const heightMatch = imgtag.match(/height[ ]?=[ ]?['"]?(\d*)['"]?/);
|
||||
const height = heightMatch ? heightMatch[1] : null;
|
||||
if (width && height) {
|
||||
const scale = Math.min(1, MessageBodyWidth / width);
|
||||
const style = ` style="height:${height * scale}px;" `
|
||||
body = body.substr(0, imgend) + style + body.substr(imgend);
|
||||
}
|
||||
}
|
||||
|
||||
result = MessageUtils.cidRegex.exec(body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue