add cfg dropdowns, collapse folders handler
parent
97d7dc3e9f
commit
0f38cac953
7
mail.css
7
mail.css
|
@ -875,11 +875,16 @@ div
|
|||
border-bottom: 1px solid #dadce0;
|
||||
}
|
||||
|
||||
.message-list .listview .day-list:last-child .thread:last-child .message:last-child
|
||||
.message-list .listview .day-list .thread:last-child .message:last-child
|
||||
{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.message-list .listview .day-list:last-child .thread:last-child .message:last-child
|
||||
{
|
||||
border-bottom: 1px solid #dadce0;
|
||||
}
|
||||
|
||||
.message-list .listview .message .icon
|
||||
{
|
||||
position: absolute;
|
||||
|
|
98
mail.js
98
mail.js
|
@ -40,7 +40,7 @@ var DropDownBase = {
|
|||
hideAll: function()
|
||||
{
|
||||
for (var i in DropDownBase.instances)
|
||||
DropDownBase.instances[i].setState({ visible: false });
|
||||
DropDownBase.instances[i].hide();
|
||||
},
|
||||
componentWillUnmount: function()
|
||||
{
|
||||
|
@ -57,9 +57,19 @@ var DropDownBase = {
|
|||
hide: function()
|
||||
{
|
||||
this.setState({ visible: false });
|
||||
if (this.onClose)
|
||||
{
|
||||
this.onClose();
|
||||
delete this.onClose;
|
||||
}
|
||||
},
|
||||
showAt: function(el)
|
||||
showAt: function(el, onClose)
|
||||
{
|
||||
if (this.onClose)
|
||||
{
|
||||
this.onClose();
|
||||
delete this.onClose;
|
||||
}
|
||||
// TODO: move on window resize
|
||||
var p = getOffset(el);
|
||||
var left = p.left, top = p.top+el.offsetHeight, calloutLeft = null;
|
||||
|
@ -81,18 +91,23 @@ var DropDownBase = {
|
|||
top = wh-this.refs.dd.offsetHeight;
|
||||
this.setState({ visible: true, top: top, left: left, calloutLeft: calloutLeft });
|
||||
this.refs.dd.focus();
|
||||
this.onClose = onClose;
|
||||
}
|
||||
};
|
||||
|
||||
var DropDownMenu = React.createClass({
|
||||
mixins: [ DropDownBase ],
|
||||
getInitialState: function()
|
||||
{
|
||||
return { items: this.props.items };
|
||||
},
|
||||
render: function()
|
||||
{
|
||||
var sel = this.state.selectedItem;
|
||||
return <div ref="dd" className={'dropdown'+(this.state.visible ? ' visible' : '')} id={'dropdown-'+this.props.id}
|
||||
tabIndex="1" style={{ top: this.state.top, left: this.state.left }} onClick={this.myOnClick} onKeyDown={this.onKeyDown}
|
||||
onMouseOver={this.onMouseOver}>
|
||||
{this.props.items.map(function(i, index) {
|
||||
{this.state.items.map(function(i, index) {
|
||||
return (i.split
|
||||
? <div key={index} className="split"><i></i></div> :
|
||||
<div key={index} data-index={index} className={'item'+(i.i16 ? ' i16' : '')+(i.disabled ? ' disabled' : (sel == index ? ' over' : ''))}>
|
||||
|
@ -116,13 +131,13 @@ var DropDownMenu = React.createClass({
|
|||
{
|
||||
if (ev.keyCode == 40 || ev.keyCode == 38)
|
||||
{
|
||||
var a = ev.keyCode == 40 ? 1 : this.props.items.length-1;
|
||||
var a = ev.keyCode == 40 ? 1 : this.state.items.length-1;
|
||||
var sel = this.state.selectedItem;
|
||||
do
|
||||
{
|
||||
sel = ((sel+a) % this.props.items.length);
|
||||
sel = ((sel+a) % this.state.items.length);
|
||||
}
|
||||
while (this.props.items[sel].split && sel != this.state.selectedItem);
|
||||
while (this.state.items[sel].split && sel != this.state.selectedItem);
|
||||
this.setState({ selectedItem: sel });
|
||||
}
|
||||
else if (ev.keyCode == 10 || ev.keyCode == 13)
|
||||
|
@ -457,16 +472,17 @@ var AccountFolders = React.createClass({
|
|||
render: function()
|
||||
{
|
||||
return <div className="account">
|
||||
<div className={"account-header"+(this.state.collapsed ? ' collapsed' : '')}>
|
||||
<div className={"account-header"+(this.state.collapsed ? ' collapsed' : '')} onClick={this.onClick}>
|
||||
{this.props.name}
|
||||
{this.props.accountId ? [
|
||||
<div key="load" className="loading icon" style={{display: this.props.loading ? '' : 'none'}}></div>,
|
||||
<div key="warn" className="warning icon" style={{display: this.props.warning ? '' : 'none'}}></div>,
|
||||
<div key="cfg" className="cfg"></div>
|
||||
<div key="cfg" className={'cfg'+(this.state.cfgPressed ? ' pressed' : '')} onClick={this.showCfg}></div>
|
||||
] : null}
|
||||
<div key="n" className="msg-count">{this.props.unreadCount}</div>
|
||||
</div>
|
||||
<div className={"account-folders"+(this.props.collapsed ? ' collapsed' : '')}><div className="visible-part">
|
||||
<div className={"account-folders"+(this.state.collapsed ? ' collapsed' : '')} style={{ height: this.state.h }}>
|
||||
<div ref="vis" className={'visible-part'+(this.state.animating ? ' animating' : '')}>
|
||||
{this.props.folders.map((f, i) =>
|
||||
<div key={'f'+i} className={'folder'+(f.unreadCount > 0 ? ' with-unread' : '')+(f.selected ? ' selected' : '')}>
|
||||
{f.icon ? <img src={'icons/'+f.icon+'.png'} /> : null}
|
||||
|
@ -475,12 +491,44 @@ var AccountFolders = React.createClass({
|
|||
{f.unreadCount > 0 ? <div className="msg-count">{f.unreadCount}</div> : null}
|
||||
</div>
|
||||
)}
|
||||
</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
},
|
||||
showCfg: function(ev)
|
||||
{
|
||||
var self = this;
|
||||
var i = DropDownBase.instances.account.state.items;
|
||||
i[0].text = 'Read '+this.props.name;
|
||||
DropDownBase.instances.account.setState({ items: i });
|
||||
DropDownBase.instances.account.showAt(ev.target, function()
|
||||
{
|
||||
self.setState({ cfgPressed: false });
|
||||
});
|
||||
self.setState({ cfgPressed: true });
|
||||
ev.stopPropagation();
|
||||
},
|
||||
getInitialState: function()
|
||||
{
|
||||
return { collapsed: this.props.collapsed };
|
||||
return { collapsed: this.props.collapsed, animating: false, h: null, cfgPressed: false };
|
||||
},
|
||||
onClick: function()
|
||||
{
|
||||
var self = this;
|
||||
if (this.state.animating)
|
||||
return;
|
||||
this.setState({ animating: true, h: this.refs.vis.offsetHeight });
|
||||
if (!this.state.collapsed)
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
self.setState({ h: 0 });
|
||||
}, 50);
|
||||
}
|
||||
setTimeout(function()
|
||||
{
|
||||
self.setState({ collapsed: !self.state.collapsed, animating: false, h: null });
|
||||
}, this.state.collapsed ? 200 : 250);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -592,6 +640,7 @@ var TabPanel = React.createClass({
|
|||
|
||||
function formatBytes(s)
|
||||
{
|
||||
if (!s) return '';
|
||||
if (s < 1024) return s+' B';
|
||||
else if (s < 1024*1024) return (Math.round(s*10/1024)/10)+' KB';
|
||||
else if (s < 1024*1024*1024) return (Math.round(s*10/1024/1024)/10)+' MB';
|
||||
|
@ -600,7 +649,7 @@ function formatBytes(s)
|
|||
|
||||
function formatDate(dt)
|
||||
{
|
||||
if (!dt instanceof Date)
|
||||
if (!(dt instanceof Date))
|
||||
dt = new Date(dt);
|
||||
var tod = new Date();
|
||||
tod.setHours(0);
|
||||
|
@ -619,10 +668,10 @@ function formatDate(dt)
|
|||
{
|
||||
var wd = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
|
||||
var mon = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
|
||||
return wd[d.getDay()]+' '+d.getDate()+' '+mon[d.getMonth()];
|
||||
return wd[dt.getDay()]+' '+dt.getDate()+' '+mon[dt.getMonth()];
|
||||
}
|
||||
var h = d.getHours();
|
||||
var m = d.getMinutes();
|
||||
var h = dt.getHours();
|
||||
var m = dt.getMinutes();
|
||||
return (h < 10 ? '0' : '')+h+':'+(m < 10 ? '0' : '')+m;
|
||||
}
|
||||
|
||||
|
@ -694,7 +743,7 @@ var ComposeWindow = React.createClass({
|
|||
<div className="no-attach" style={this.state.attachments.length ? { display: 'none' } : null}>
|
||||
<input type="file" multiple="multiple" onChange={this.addAttachments} />
|
||||
</div>
|
||||
<div className="attach-list" tabindex="1" onScroll={this.scrollAttachList}
|
||||
<div className="attach-list" tabIndex="1" onScroll={this.scrollAttachList}
|
||||
style={this.state.attachments.length ? null : { display: 'none' }}>
|
||||
<div className="title" style={{ top: this.state.attachScroll }}>
|
||||
<div className="name">Attachment <a className="button">
|
||||
|
@ -728,7 +777,7 @@ var MessageInList = React.createClass({
|
|||
return <div className={'message'+(this.msgClasses.map(c => (msg[c] ? ' '+c : '')).join(''))+(msg.thread ? ' thread0' : '')}>
|
||||
<div className="icon" style={{ width: (20+10*msg.level), backgroundPosition: (10*msg.level)+'px 7px' }}></div>
|
||||
<div className="subject">{msg.subject}</div>
|
||||
{msg.thread ? <div className={'expand'+(msg.expanded ? ' collapse' : '')}></div> : null}
|
||||
{msg.thread ? <div className={'expand'+(msg.collapsed ? '' : ' collapse')}></div> : null}
|
||||
<div className="bullet"></div>
|
||||
<div className="from" style={{ left: (21+10*msg.level) }}>{(msg.sent || msg.outgoing ? 'To '+msg.to : msg.from)}</div>
|
||||
<div className="size">{formatBytes(msg.size)}</div>
|
||||
|
@ -764,7 +813,7 @@ var MessageList = React.createClass({
|
|||
title="Sorting settings" icon="list_sort" />
|
||||
<div className="clear"></div>
|
||||
</div>
|
||||
<div className="listview" tabindex="1" onScroll={this.changeFirstDay}>
|
||||
<div className="listview" tabIndex="1" onScroll={this.changeFirstDay}>
|
||||
<div className="day first-day" style={{ top: this.state.firstDayTop }}>{this.props.groups[0].name}</div>
|
||||
{this.props.groups.map((grp, i) => [
|
||||
i > 0 ? <div className="day">{grp.name}</div> : null,
|
||||
|
@ -922,7 +971,18 @@ var composeAccounts = [
|
|||
|
||||
var listGroups = [ {
|
||||
name: 'TODAY',
|
||||
messages: []
|
||||
messages: [ {
|
||||
subject: 'кошку хочешь?))',
|
||||
sent: true,
|
||||
to: 'Margarita Philippova',
|
||||
date: '2016-06-14 21:24',
|
||||
thread: [ {
|
||||
subject: 'Re: кошку хочешь?))',
|
||||
from: 'Margarita Philippova',
|
||||
date: '2016-06-14 22:31',
|
||||
level: 1
|
||||
} ]
|
||||
} ]
|
||||
} ];
|
||||
|
||||
ReactDOM.render(
|
||||
|
|
Loading…
Reference in New Issue