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;
|
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;
|
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
|
.message-list .listview .message .icon
|
||||||
{
|
{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
98
mail.js
98
mail.js
|
@ -40,7 +40,7 @@ var DropDownBase = {
|
||||||
hideAll: function()
|
hideAll: function()
|
||||||
{
|
{
|
||||||
for (var i in DropDownBase.instances)
|
for (var i in DropDownBase.instances)
|
||||||
DropDownBase.instances[i].setState({ visible: false });
|
DropDownBase.instances[i].hide();
|
||||||
},
|
},
|
||||||
componentWillUnmount: function()
|
componentWillUnmount: function()
|
||||||
{
|
{
|
||||||
|
@ -57,9 +57,19 @@ var DropDownBase = {
|
||||||
hide: function()
|
hide: function()
|
||||||
{
|
{
|
||||||
this.setState({ visible: false });
|
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
|
// TODO: move on window resize
|
||||||
var p = getOffset(el);
|
var p = getOffset(el);
|
||||||
var left = p.left, top = p.top+el.offsetHeight, calloutLeft = null;
|
var left = p.left, top = p.top+el.offsetHeight, calloutLeft = null;
|
||||||
|
@ -81,18 +91,23 @@ var DropDownBase = {
|
||||||
top = wh-this.refs.dd.offsetHeight;
|
top = wh-this.refs.dd.offsetHeight;
|
||||||
this.setState({ visible: true, top: top, left: left, calloutLeft: calloutLeft });
|
this.setState({ visible: true, top: top, left: left, calloutLeft: calloutLeft });
|
||||||
this.refs.dd.focus();
|
this.refs.dd.focus();
|
||||||
|
this.onClose = onClose;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var DropDownMenu = React.createClass({
|
var DropDownMenu = React.createClass({
|
||||||
mixins: [ DropDownBase ],
|
mixins: [ DropDownBase ],
|
||||||
|
getInitialState: function()
|
||||||
|
{
|
||||||
|
return { items: this.props.items };
|
||||||
|
},
|
||||||
render: function()
|
render: function()
|
||||||
{
|
{
|
||||||
var sel = this.state.selectedItem;
|
var sel = this.state.selectedItem;
|
||||||
return <div ref="dd" className={'dropdown'+(this.state.visible ? ' visible' : '')} id={'dropdown-'+this.props.id}
|
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}
|
tabIndex="1" style={{ top: this.state.top, left: this.state.left }} onClick={this.myOnClick} onKeyDown={this.onKeyDown}
|
||||||
onMouseOver={this.onMouseOver}>
|
onMouseOver={this.onMouseOver}>
|
||||||
{this.props.items.map(function(i, index) {
|
{this.state.items.map(function(i, index) {
|
||||||
return (i.split
|
return (i.split
|
||||||
? <div key={index} className="split"><i></i></div> :
|
? <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' : ''))}>
|
<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)
|
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;
|
var sel = this.state.selectedItem;
|
||||||
do
|
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 });
|
this.setState({ selectedItem: sel });
|
||||||
}
|
}
|
||||||
else if (ev.keyCode == 10 || ev.keyCode == 13)
|
else if (ev.keyCode == 10 || ev.keyCode == 13)
|
||||||
|
@ -457,16 +472,17 @@ var AccountFolders = React.createClass({
|
||||||
render: function()
|
render: function()
|
||||||
{
|
{
|
||||||
return <div className="account">
|
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.name}
|
||||||
{this.props.accountId ? [
|
{this.props.accountId ? [
|
||||||
<div key="load" className="loading icon" style={{display: this.props.loading ? '' : 'none'}}></div>,
|
<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="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}
|
] : null}
|
||||||
<div key="n" className="msg-count">{this.props.unreadCount}</div>
|
<div key="n" className="msg-count">{this.props.unreadCount}</div>
|
||||||
</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) =>
|
{this.props.folders.map((f, i) =>
|
||||||
<div key={'f'+i} className={'folder'+(f.unreadCount > 0 ? ' with-unread' : '')+(f.selected ? ' selected' : '')}>
|
<div key={'f'+i} className={'folder'+(f.unreadCount > 0 ? ' with-unread' : '')+(f.selected ? ' selected' : '')}>
|
||||||
{f.icon ? <img src={'icons/'+f.icon+'.png'} /> : null}
|
{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}
|
{f.unreadCount > 0 ? <div className="msg-count">{f.unreadCount}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</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()
|
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)
|
function formatBytes(s)
|
||||||
{
|
{
|
||||||
|
if (!s) return '';
|
||||||
if (s < 1024) return s+' B';
|
if (s < 1024) return s+' B';
|
||||||
else if (s < 1024*1024) return (Math.round(s*10/1024)/10)+' KB';
|
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';
|
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)
|
function formatDate(dt)
|
||||||
{
|
{
|
||||||
if (!dt instanceof Date)
|
if (!(dt instanceof Date))
|
||||||
dt = new Date(dt);
|
dt = new Date(dt);
|
||||||
var tod = new Date();
|
var tod = new Date();
|
||||||
tod.setHours(0);
|
tod.setHours(0);
|
||||||
|
@ -619,10 +668,10 @@ function formatDate(dt)
|
||||||
{
|
{
|
||||||
var wd = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
|
var wd = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];
|
||||||
var mon = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
|
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 h = dt.getHours();
|
||||||
var m = d.getMinutes();
|
var m = dt.getMinutes();
|
||||||
return (h < 10 ? '0' : '')+h+':'+(m < 10 ? '0' : '')+m;
|
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}>
|
<div className="no-attach" style={this.state.attachments.length ? { display: 'none' } : null}>
|
||||||
<input type="file" multiple="multiple" onChange={this.addAttachments} />
|
<input type="file" multiple="multiple" onChange={this.addAttachments} />
|
||||||
</div>
|
</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' }}>
|
style={this.state.attachments.length ? null : { display: 'none' }}>
|
||||||
<div className="title" style={{ top: this.state.attachScroll }}>
|
<div className="title" style={{ top: this.state.attachScroll }}>
|
||||||
<div className="name">Attachment <a className="button">
|
<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' : '')}>
|
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="icon" style={{ width: (20+10*msg.level), backgroundPosition: (10*msg.level)+'px 7px' }}></div>
|
||||||
<div className="subject">{msg.subject}</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="bullet"></div>
|
||||||
<div className="from" style={{ left: (21+10*msg.level) }}>{(msg.sent || msg.outgoing ? 'To '+msg.to : msg.from)}</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>
|
<div className="size">{formatBytes(msg.size)}</div>
|
||||||
|
@ -764,7 +813,7 @@ var MessageList = React.createClass({
|
||||||
title="Sorting settings" icon="list_sort" />
|
title="Sorting settings" icon="list_sort" />
|
||||||
<div className="clear"></div>
|
<div className="clear"></div>
|
||||||
</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>
|
<div className="day first-day" style={{ top: this.state.firstDayTop }}>{this.props.groups[0].name}</div>
|
||||||
{this.props.groups.map((grp, i) => [
|
{this.props.groups.map((grp, i) => [
|
||||||
i > 0 ? <div className="day">{grp.name}</div> : null,
|
i > 0 ? <div className="day">{grp.name}</div> : null,
|
||||||
|
@ -922,7 +971,18 @@ var composeAccounts = [
|
||||||
|
|
||||||
var listGroups = [ {
|
var listGroups = [ {
|
||||||
name: 'TODAY',
|
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(
|
ReactDOM.render(
|
||||||
|
|
Loading…
Reference in New Issue