Implement image/css blocking, fix "Settings" button migration and some errors
parent
6d2b3e2aa9
commit
ea874385c1
|
@ -2,9 +2,9 @@ const React = require('react');
|
||||||
const DropDownBase = require('./DropDownBase.js');
|
const DropDownBase = require('./DropDownBase.js');
|
||||||
|
|
||||||
var DropDownButton = module.exports = React.createClass({
|
var DropDownButton = module.exports = React.createClass({
|
||||||
componentWillReceiveProps: function(nextProps)
|
componentDidUpdate: function(prevProps, prevState)
|
||||||
{
|
{
|
||||||
if (!nextProps.hidden && this.props.hidden &&
|
if (prevProps.hidden && !this.props.hidden &&
|
||||||
DropDownBase.instances[this.props.dropdownId].isVisible())
|
DropDownBase.instances[this.props.dropdownId].isVisible())
|
||||||
{
|
{
|
||||||
DropDownBase.instances[this.props.dropdownId].showAt(this.refs.btn, this.unpress);
|
DropDownBase.instances[this.props.dropdownId].showAt(this.refs.btn, this.unpress);
|
||||||
|
@ -14,7 +14,7 @@ var DropDownButton = module.exports = React.createClass({
|
||||||
{
|
{
|
||||||
return <a ref="btn" title={(this.state.checked ? this.props.checkedTitle : null) || this.props.title} onClick={this.onClickButton}
|
return <a ref="btn" title={(this.state.checked ? this.props.checkedTitle : null) || this.props.title} onClick={this.onClickButton}
|
||||||
className={'button '+(this.props.dropdownId ? 'show-dropdown ' : '')+(this.state.checked ? 'checked ' : '')+
|
className={'button '+(this.props.dropdownId ? 'show-dropdown ' : '')+(this.state.checked ? 'checked ' : '')+
|
||||||
(this.state.hidden ? 'hidden ' : '')+
|
(this.props.hidden ? 'hidden ' : '')+
|
||||||
(this.state.pressed ? 'pressed ' : '')+(this.props.className || '')}>
|
(this.state.pressed ? 'pressed ' : '')+(this.props.className || '')}>
|
||||||
{this.props.icon ? <img src={'icons/'+(this.state.checked && this.props.checkedIcon || this.props.icon)+'.png'} /> : null}
|
{this.props.icon ? <img src={'icons/'+(this.state.checked && this.props.checkedIcon || this.props.icon)+'.png'} /> : null}
|
||||||
{this.state.checked && this.props.checkedText || this.props.text || null}
|
{this.state.checked && this.props.checkedText || this.props.text || null}
|
||||||
|
|
|
@ -21,7 +21,7 @@ var MailSettingsWindow = React.createClass({
|
||||||
<div className="text">Default List Sorting</div>
|
<div className="text">Default List Sorting</div>
|
||||||
<ListSortSettings className="fields" sort={this.props.defaultSorting} />
|
<ListSortSettings className="fields" sort={this.props.defaultSorting} />
|
||||||
<div className="fields">
|
<div className="fields">
|
||||||
<label><input type="checkbox" checked={this.props.showQuickReply} onClick={this.showQuickReply} /> Show Quick Reply</label>
|
<label><input type="checkbox" checked={this.props.quickReply} onClick={this.showQuickReply} /> Show Quick Reply</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="split"><i></i></div>
|
<div className="split"><i></i></div>
|
||||||
<div className="text">Mark as Read</div>
|
<div className="text">Mark as Read</div>
|
||||||
|
@ -44,13 +44,13 @@ var MailSettingsWindow = React.createClass({
|
||||||
},
|
},
|
||||||
showQuickReply: function()
|
showQuickReply: function()
|
||||||
{
|
{
|
||||||
Store.set('quickReply', !this.state.showQuickReply);
|
Store.set('quickReply', !this.props.quickReply);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = StoreListener(
|
module.exports = StoreListener(
|
||||||
MailSettingsWindow,
|
MailSettingsWindow,
|
||||||
(data) => { return { layout: data.layout, showQuickReply: data.showQuickReply }; },
|
(data) => { return { layout: data.layout, quickReply: data.quickReply }; },
|
||||||
{
|
{
|
||||||
id: 'settings',
|
id: 'settings',
|
||||||
window: true,
|
window: true,
|
||||||
|
|
|
@ -38,7 +38,7 @@ var MessageList = React.createClass({
|
||||||
setFirstDayFromProps: function(props)
|
setFirstDayFromProps: function(props)
|
||||||
{
|
{
|
||||||
var groups = props.groups;
|
var groups = props.groups;
|
||||||
if (!groups.length)
|
if (!groups || !groups.length)
|
||||||
return;
|
return;
|
||||||
var scrollTop = this.refs.scroll.scrollTop, scrollSize = this.refs.scroll.offsetHeight - this.getScrollPaddingTop();
|
var scrollTop = this.refs.scroll.scrollTop, scrollSize = this.refs.scroll.offsetHeight - this.getScrollPaddingTop();
|
||||||
var top = 0, p, firstVisibleGrp, firstVisible, lastVisibleGrp, lastVisible;
|
var top = 0, p, firstVisibleGrp, firstVisible, lastVisibleGrp, lastVisible;
|
||||||
|
@ -95,7 +95,7 @@ var MessageList = React.createClass({
|
||||||
{
|
{
|
||||||
var self = this;
|
var self = this;
|
||||||
var total = 0, p, msg, idx;
|
var total = 0, p, msg, idx;
|
||||||
for (var i = 0; i < self.props.groups.length; i++)
|
for (var i = 0; i < (self.props.groups||[]).length; i++)
|
||||||
{
|
{
|
||||||
p = total;
|
p = total;
|
||||||
total += (i > 0 ? 1 : 0)+self.props.groups[i].messageCount;
|
total += (i > 0 ? 1 : 0)+self.props.groups[i].messageCount;
|
||||||
|
@ -123,7 +123,7 @@ var MessageList = React.createClass({
|
||||||
getTotalItems: function()
|
getTotalItems: function()
|
||||||
{
|
{
|
||||||
var total = -1; // do not count first-day as item
|
var total = -1; // do not count first-day as item
|
||||||
for (var i = 0; i < this.props.groups.length; i++)
|
for (var i = 0; i < (this.props.groups||[]).length; i++)
|
||||||
{
|
{
|
||||||
total += 1+this.props.groups[i].messageCount;
|
total += 1+this.props.groups[i].messageCount;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ var MessageList = React.createClass({
|
||||||
getItemOffset: function(index)
|
getItemOffset: function(index)
|
||||||
{
|
{
|
||||||
var n = 0, top = this.refs.title.offsetHeight, p;
|
var n = 0, top = this.refs.title.offsetHeight, p;
|
||||||
for (var i = 0; i < this.props.groups.length; i++)
|
for (var i = 0; i < (this.props.groups||[]).length; i++)
|
||||||
{
|
{
|
||||||
p = n;
|
p = n;
|
||||||
n += (i > 0 ? 1 : 0)+this.props.groups[i].messageCount;
|
n += (i > 0 ? 1 : 0)+this.props.groups[i].messageCount;
|
||||||
|
|
|
@ -15,9 +15,44 @@ var MessageView = React.createClass({
|
||||||
return Util.WeekDays[dt.getDay()]+' '+dt.getDate()+' '+Util.Months[dt.getMonth()]+' '+dt.getFullYear()+' '+(h < 10 ? '0' : '')+h+':'+(m < 10 ? '0' : '')+m+':'+(s < 10 ? '0' : '')+s
|
return Util.WeekDays[dt.getDay()]+' '+dt.getDate()+' '+Util.Months[dt.getMonth()]+' '+dt.getFullYear()+' '+(h < 10 ? '0' : '')+h+':'+(m < 10 ? '0' : '')+m+':'+(s < 10 ? '0' : '')+s
|
||||||
//return dt.toLocaleString();
|
//return dt.toLocaleString();
|
||||||
},
|
},
|
||||||
|
componentWillReceiveProps: function(nextProps)
|
||||||
|
{
|
||||||
|
if (nextProps.msg != this.props.msg)
|
||||||
|
{
|
||||||
|
var ns = { showImages: false, blockedImages: false };
|
||||||
|
if (/<img[^>]*>/i.exec(nextProps.msg.body_html))
|
||||||
|
{
|
||||||
|
ns.blockedImages = true;
|
||||||
|
}
|
||||||
|
this.setState(ns);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showImages: function()
|
||||||
|
{
|
||||||
|
this.setState({ showImages: true });
|
||||||
|
},
|
||||||
|
getInitialState: function()
|
||||||
|
{
|
||||||
|
return { showImages: false };
|
||||||
|
},
|
||||||
render: function()
|
render: function()
|
||||||
{
|
{
|
||||||
|
var showImages = this.state.showImages;
|
||||||
var msg = this.props.msg;
|
var msg = this.props.msg;
|
||||||
|
var html;
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
html = msg.body_html;
|
||||||
|
if (!showImages)
|
||||||
|
{
|
||||||
|
html = html.replace(/(<img[^>]*?src=)(["'])([^'"]*\2)/ig, '$1$2blocked:$3');
|
||||||
|
html = html.replace(/<style[^>]*>(.*)<\/style\s*>/ig, function(m, m1)
|
||||||
|
{
|
||||||
|
m1 = m1.replace(/(url\(["']?|\@import\s*["'])([^"']*)/ig, '$1blocked:$2');
|
||||||
|
return '<style>'+m1+'</style>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return <div className={'message-view'+(!msg ? ' no-mail-shown' : '')+(!this.props.quickReply ? ' no-quick' : '')}>
|
return <div className={'message-view'+(!msg ? ' no-mail-shown' : '')+(!this.props.quickReply ? ' no-quick' : '')}>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<DropDownButton dropdownId="reply" icon="mail_reply" text="Reply" />
|
<DropDownButton dropdownId="reply" icon="mail_reply" text="Reply" />
|
||||||
|
@ -69,15 +104,15 @@ var MessageView = React.createClass({
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
(msg.blockedImages
|
(this.state.blockedImages && !this.state.showImages
|
||||||
? <div className="blocked-images">
|
? <div className="blocked-images">
|
||||||
<img src="icons/block.png" /> This message contains blocked images.
|
<img src="icons/block.png" /> This message contains blocked images.
|
||||||
<a className="button raised">Load Images</a>
|
<a className="button raised" onClick={this.showImages}>Load Images</a>
|
||||||
<label><input type="checkbox" /> Always load from {msg.from}</label>
|
<label><input type="checkbox" /> Always load from {msg.from_email}</label>
|
||||||
</div>
|
</div>
|
||||||
: null),
|
: null),
|
||||||
(msg.body_html
|
(html
|
||||||
? <div className="text" dangerouslySetInnerHTML={{ __html: msg.body_html }}></div>
|
? <div className="text" dangerouslySetInnerHTML={{ __html: html }}></div>
|
||||||
: <div className="text plain">{msg.body_text}</div>
|
: <div className="text plain">{msg.body_text}</div>
|
||||||
),
|
),
|
||||||
(this.props.quickReply
|
(this.props.quickReply
|
||||||
|
|
17
mail.css
17
mail.css
|
@ -137,6 +137,11 @@ div
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.show-dropdown.hidden
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.show-dropdown .down
|
.show-dropdown .down
|
||||||
{
|
{
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -753,13 +758,6 @@ div
|
||||||
.message-list .actions .settings
|
.message-list .actions .settings
|
||||||
{
|
{
|
||||||
float: right;
|
float: right;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-on-bottom .message-list .actions .settings,
|
|
||||||
.message-invisible .message-list .actions .settings
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-list .listview
|
.message-list .listview
|
||||||
|
@ -1178,11 +1176,6 @@ div
|
||||||
border-bottom: 1px solid #aca9a7;
|
border-bottom: 1px solid #aca9a7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-on-bottom .message-view .actions .settings
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-view
|
.message-view
|
||||||
{
|
{
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -81,3 +81,19 @@ a.button .img
|
||||||
{
|
{
|
||||||
content: "Undelete";
|
content: "Undelete";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-list .actions .settings
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-on-bottom .message-list .actions .settings,
|
||||||
|
.message-invisible .message-list .actions .settings
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-on-bottom .message-view .actions .settings
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue