add cfg dropdowns, collapse folders handler

master
Vitaliy Filippov 2016-06-21 22:55:28 +03:00
parent 97d7dc3e9f
commit 0f38cac953
2 changed files with 85 additions and 20 deletions

View File

@ -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
View File

@ -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(