Implement basic virtual scroll

master
Vitaliy Filippov 2016-06-24 15:43:44 +03:00
parent 81629f0614
commit 78fc90e1ef
1 changed files with 77 additions and 33 deletions

110
mail.js
View File

@ -1041,20 +1041,34 @@ var MessageList = React.createClass({
if (i > 0 && scrollTop < p+30)
firstVisible = 0;
else
firstVisible = Math.floor((scrollTop - (i > 0 ? 30 : 0))/itemH);
firstVisible = Math.floor((scrollTop - p - (i > 0 ? 30 : 0))/itemH);
}
if (lastVisibleGrp === undefined && scrollTop+scrollSize < top)
{
lastVisibleGrp = i;
if (i > 0 && scrollTop < p+30)
if (i > 0 && scrollTop+scrollSize < p+30)
lastVisible = 0;
else
lastVisible = Math.floor((scrollTop+scrollSize+itemH-1 - (i > 0 ? 30 : 0))/itemH);
lastVisible = Math.floor((scrollTop+scrollSize - p - (i > 0 ? 30 : 0))/itemH);
if (lastVisible >= this.state.groups[i].messageCount)
lastVisible = this.state.groups[i].messageCount-1;
}
if (firstVisibleGrp !== undefined && lastVisibleGrp !== undefined)
break;
}
this.setState({ firstDayTop: scrollTop, firstDay: this.state.groups[firstVisibleGrp].name });
if (lastVisibleGrp === undefined)
{
lastVisibleGrp = this.state.groups.length-1;
lastVisible = this.state.groups[lastVisibleGrp].messageCount-1;
}
this.setState({
firstDayTop: scrollTop,
firstDay: this.state.groups[firstVisibleGrp].name,
firstGrp: firstVisibleGrp,
firstMsg: firstVisible,
lastGrp: lastVisibleGrp,
lastMsg: lastVisible
});
},
deleteSelected: function()
{
@ -1114,10 +1128,19 @@ var MessageList = React.createClass({
{
return this.refs.title.offsetHeight;
},
getMessages: function(grp, start, end)
{
var a = grp.messages.slice(start, end);
for (var i = 0; i < end-start; i++)
if (!a[i])
a[i] = null;
return a;
},
render: function()
{
var self = this;
var total = 0;
var itemH = (Store.layout == 'message-on-right' ? 60 : 30);
return <div className="message-list">
<div className="top-border-gradient"></div>
<div className="bottom-border-gradient"></div>
@ -1138,20 +1161,38 @@ var MessageList = React.createClass({
{this.props.groups.map(function(grp, i) {
if (i > 0)
total++;
var start = total+(self.state.firstGrp == i ? self.state.firstMsg : 0);
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} i={0} onClick={self.onListItemClick} />)}
</div>
: null)
])}
{(self.state.firstGrp > i || self.state.lastGrp < i
? <div className="placeholder" style={{ height: itemH*grp.messageCount }}></div>
: [
(self.state.firstGrp == i
? <div className="placeholder" style={{ height: itemH*self.state.firstMsg }}></div>
: null),
self.getMessages(grp,
self.state.firstGrp == i ? self.state.firstMsg : 0,
self.state.lastGrp == i ? self.state.lastMsg+1 : grp.messageCount
).map((msg, j) => (msg
? [
<MessageInList msg={msg} i={start+j} selected={self.isSelected(start+j)} onClick={self.onListItemClick} />,
/*(msg.thread && Store.threads ?
<div className="thread">
{msg.thread.map(reply => <MessageInList msg={reply} i={0} onClick={self.onListItemClick} />)}
</div>
: null)*/
]
: <div data-i={start+j} className={'message'+(self.isSelected(start+j) ? ' selected' : '')} onMouseDown={self.onListItemClick}></div>
)),
(self.state.lastGrp == i
? <div className="placeholder" style={{ height: itemH*(grp.messageCount-self.state.lastMsg-1) }}></div>
: null)
]
)}
</div>
];
total += grp.messages.length;
total += grp.messageCount;
return r;
})}
</div>
@ -1325,9 +1366,29 @@ var composeAccounts = [
{ name: 'Vitaliy Filippov', email: 'vitalif@yourcmc.ru' }
];
var msg2 = [];
msg2[5] = {
subject: 'кошку хочешь?))',
sent: true,
from: 'Виталий Филиппов',
fromEmail: 'vitalif@mail.ru',
to: 'Margarita Philippova',
time: '2016-06-14 21:24',
body: 'к нам тут пришла какая-то и к нам в дом рвётся, симпатишная) потеряшка какая-то, но явно домашняя, не боится людей))',
thread: [ {
subject: 'Re: кошку хочешь?))',
from: 'Margarita Philippova',
fromEmail: 'philippova.marga@gmail.com',
to: 'Виталий Филиппов',
time: '2016-06-14 22:31',
level: 1,
body: 'Нет, конечно, не хочу. Я уеду в Баку, а кошка как? Уеду в Астану - а кошка как? Наташа меня Сухорукова приглашает в Барселону - а кошку куда? Я только испытала радость облегчения от того, что у меня больше нет горшочных цветов - и кошку мне? НЕт! Папику предложи - у него уже много зверья, одной кошкой больше - одной меньше - какая разница?'
} ]
};
var listGroups = [ {
name: 'TODAY',
messageCount: 1,
messageCount: 10,
messages: [ {
subject: 'The Glossary of Happiness By Emily Anthes , May 12, 2016',
from: 'Margarita Philippova',
@ -1343,25 +1404,8 @@ Best regards,<br />\
} ]
}, {
name: 'LAST WEEK',
messageCount: 1,
messages: [ {
subject: 'кошку хочешь?))',
sent: true,
from: 'Виталий Филиппов',
fromEmail: 'vitalif@mail.ru',
to: 'Margarita Philippova',
time: '2016-06-14 21:24',
body: 'к нам тут пришла какая-то и к нам в дом рвётся, симпатишная) потеряшка какая-то, но явно домашняя, не боится людей))',
thread: [ {
subject: 'Re: кошку хочешь?))',
from: 'Margarita Philippova',
fromEmail: 'philippova.marga@gmail.com',
to: 'Виталий Филиппов',
time: '2016-06-14 22:31',
level: 1,
body: 'Нет, конечно, не хочу. Я уеду в Баку, а кошка как? Уеду в Астану - а кошка как? Наташа меня Сухорукова приглашает в Барселону - а кошку куда? Я только испытала радость облегчения от того, что у меня больше нет горшочных цветов - и кошку мне? НЕт! Папику предложи - у него уже много зверья, одной кошкой больше - одной меньше - какая разница?'
} ]
} ]
messageCount: 15,
messages: msg2
} ];
var AllTabs = React.createClass({