Use selection mixin in message list
parent
617d90757e
commit
27552f167d
5
mail.css
5
mail.css
|
@ -872,6 +872,11 @@ div
|
|||
border-bottom: 1px solid #dadce0;
|
||||
}
|
||||
|
||||
.message-list .listview .day-list .message:last-child
|
||||
{
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.message-list .listview .day-list .thread:last-child .message:last-child
|
||||
{
|
||||
border-bottom: 0;
|
||||
|
|
112
mail.js
112
mail.js
|
@ -769,11 +769,11 @@ var ListWithSelection = {
|
|||
dir = (ev.keyCode == 40 ? 1 : -1);
|
||||
if (sel !== null)
|
||||
{
|
||||
var nsel = sel+dir;
|
||||
var nsel = sel+dir, n = this.getTotalItems();
|
||||
if (nsel < 0)
|
||||
nsel = 0;
|
||||
if (nsel >= this.getTotalItems())
|
||||
nsel = this.getTotalItems()-1;
|
||||
if (nsel >= n)
|
||||
nsel = n-1;
|
||||
if (sel != nsel)
|
||||
{
|
||||
if (ev.shiftKey)
|
||||
|
@ -818,8 +818,9 @@ var ListWithSelection = {
|
|||
if (this.lastSel === undefined)
|
||||
return this.selectOne(ns);
|
||||
var sel = {};
|
||||
if (this.lastSel >= this.getTotalItems())
|
||||
this.lastSel = this.getTotalItems()-1;
|
||||
var n = this.getTotalItems();
|
||||
if (this.lastSel >= n)
|
||||
this.lastSel = n-1;
|
||||
if (ns < this.lastSel)
|
||||
sel = { begin: ns, end: this.lastSel };
|
||||
else if (ns > this.lastSel)
|
||||
|
@ -994,21 +995,16 @@ var ComposeWindow = React.createClass({
|
|||
|
||||
var MessageInList = React.createClass({
|
||||
msgClasses: [ 'unread', 'unseen', 'replied', 'pinned', 'sent', 'unloaded' ],
|
||||
onClick: function()
|
||||
onClick: function(ev)
|
||||
{
|
||||
Store.set('msg', this.props.msg);
|
||||
this.setState({ selected: true });
|
||||
this.props.onClick(this);
|
||||
},
|
||||
getInitialState: function()
|
||||
{
|
||||
return { selected: false };
|
||||
this.props.onClick(ev);
|
||||
},
|
||||
render: function()
|
||||
{
|
||||
var msg = this.props.msg;
|
||||
return <div className={'message'+(this.msgClasses.map(c => (msg[c] ? ' '+c : '')).join(''))+
|
||||
(this.state.selected ? ' selected' : '')+(msg.thread && Store.threads ? ' thread0' : '')} onMouseDown={this.onClick}>
|
||||
return <div data-i={this.props.i} className={'message'+(this.msgClasses.map(c => (msg[c] ? ' '+c : '')).join(''))+
|
||||
(this.props.selected ? ' selected' : '')+(msg.thread && Store.threads ? ' thread0' : '')} onMouseDown={this.onClick}>
|
||||
<div className="icon" style={{ width: (20+10*(msg.level||0)), backgroundPosition: (10*(msg.level||0))+'px 7px' }}></div>
|
||||
<div className="subject" style={{ paddingLeft: (20+10*(msg.level||0)) }}>{msg.subject}</div>
|
||||
{msg.thread && Store.threads ? <div className={'expand'+(msg.collapsed ? '' : ' collapse')}></div> : null}
|
||||
|
@ -1023,16 +1019,63 @@ var MessageInList = React.createClass({
|
|||
|
||||
// TODO: full keyboard navigation in message list, expand/collapse days, virtual scroll...
|
||||
var MessageList = React.createClass({
|
||||
mixins: [ ListWithSelection ],
|
||||
getInitialState: function()
|
||||
{
|
||||
return { firstDayTop: 0 };
|
||||
return { firstDayTop: 0, groups: this.props.groups /*FIXME*/ };
|
||||
},
|
||||
changeFirstDay: function(ev)
|
||||
{
|
||||
this.setState({ firstDayTop: ev.target.scrollTop });
|
||||
},
|
||||
deleteSelected: function()
|
||||
{
|
||||
|
||||
},
|
||||
getTotalItems: function()
|
||||
{
|
||||
var total = 0;
|
||||
for (var i = 0; i < this.state.groups.length; i++)
|
||||
{
|
||||
total += 1+this.state.groups[i].messages.length;
|
||||
}
|
||||
return total;
|
||||
},
|
||||
getPageSize: function()
|
||||
{
|
||||
return Math.round(this.refs.scroll.offsetHeight / (Store.layout == 'message-on-right' ? 60 : 30));
|
||||
},
|
||||
getItemOffset: function(index)
|
||||
{
|
||||
/*var c, gmin = 0, gmax = this.state.groups.length;
|
||||
while (gmin != gmax-1)
|
||||
{
|
||||
c = Math.floor((gmax+gmin)/2);
|
||||
if (this.state.groups[c]
|
||||
}*/
|
||||
var n = 0, top = 0, p;
|
||||
for (var i = 0; i < this.state.groups.length; i++)
|
||||
{
|
||||
p = n;
|
||||
n += 1+this.state.groups[i].messages.length;
|
||||
if (index < n)
|
||||
{
|
||||
if (index > p)
|
||||
top += 30 + (Store.layout == 'message-on-right' ? 60 : 30)*(index-p-1);
|
||||
break;
|
||||
}
|
||||
top += 30 + (Store.layout == 'message-on-right' ? 60 : 30)*this.state.groups[i].messages.length;
|
||||
}
|
||||
return [ top, (Store.layout == 'message-on-right' && index != p ? 60 : 30) ];
|
||||
},
|
||||
getScrollPaddingTop: function()
|
||||
{
|
||||
return this.refs.title.offsetHeight;
|
||||
},
|
||||
render: function()
|
||||
{
|
||||
var self = this;
|
||||
var total = 0;
|
||||
return <div className="message-list">
|
||||
<div className="top-border-gradient"></div>
|
||||
<div className="bottom-border-gradient"></div>
|
||||
|
@ -1048,31 +1091,28 @@ 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="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,
|
||||
<div className="day-list">
|
||||
{grp.messages.map(msg => [
|
||||
<MessageInList msg={msg} onClick={this.onMsgClick} />,
|
||||
(msg.thread ?
|
||||
(Store.threads ?
|
||||
<div ref="scroll" className="listview" tabIndex="1" onScroll={this.changeFirstDay} onKeyDown={this.onListKeyDown}>
|
||||
<div ref="title" className="day first-day" style={{ top: this.state.firstDayTop }}>{this.props.groups[0].name}</div>
|
||||
{this.props.groups.map(function(grp, i) {
|
||||
total++;
|
||||
var r = [
|
||||
i > 0 ? <div className="day" data-i={total-1}>{grp.name}</div> : null,
|
||||
<div className="day-list">
|
||||
{grp.messages.map((msg, j) => [
|
||||
<MessageInList msg={msg} i={total+j} selected={self.isSelected(total+j)} onClick={self.onListItemClick} />,
|
||||
(msg.thread && Store.threads ?
|
||||
<div className="thread">
|
||||
{msg.thread.map(reply => <MessageInList msg={reply} onClick={this.onMsgClick} />)}
|
||||
{msg.thread.map(reply => <MessageInList msg={reply} i={0} onClick={self.onListItemClick} />)}
|
||||
</div>
|
||||
: msg.thread.map(reply => <MessageInList msg={reply} onClick={this.onMsgClick} />))
|
||||
: null)
|
||||
])}
|
||||
</div>
|
||||
])}
|
||||
: null)
|
||||
])}
|
||||
</div>
|
||||
];
|
||||
total += grp.messages.length;
|
||||
return r;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
},
|
||||
onMsgClick: function(msg)
|
||||
{
|
||||
if (this.prevSelected && this.prevSelected != msg)
|
||||
this.prevSelected.setState({ selected: false });
|
||||
this.prevSelected = msg;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue