140 lines
4.4 KiB
JavaScript
140 lines
4.4 KiB
JavaScript
import React from 'react';
|
|
|
|
// Common "list with selection" component
|
|
|
|
export default class ListWithSelection extends React.PureComponent
|
|
{
|
|
// requires to override methods: this.deleteSelected(), this.getPageSize(), this.getItemOffset(index), this.getTotalItems()
|
|
constructor(props)
|
|
{
|
|
super(props);
|
|
this.state = this.state||{};
|
|
this.state.selected = {};
|
|
}
|
|
|
|
isSelected(i)
|
|
{
|
|
return this.state.selected[i] || this.state.selected.begin !== undefined &&
|
|
this.state.selected.begin <= i && this.state.selected.end >= i;
|
|
}
|
|
|
|
onListKeyDown = (ev) =>
|
|
{
|
|
if (!this.getTotalItems())
|
|
return;
|
|
if (ev.keyCode == 46) // delete
|
|
{
|
|
this.deleteSelected();
|
|
this.setState({ selected: {} });
|
|
ev.stopPropagation();
|
|
}
|
|
else if (ev.keyCode == 38 || ev.keyCode == 40 || ev.keyCode == 33 || ev.keyCode == 34) // up, down, pgup, pgdown
|
|
{
|
|
let sel = this.curSel, dir;
|
|
if (ev.keyCode < 35)
|
|
dir = (ev.keyCode == 34 ? 1 : -1) * this.getPageSize();
|
|
else
|
|
dir = (ev.keyCode == 40 ? 1 : -1);
|
|
if (sel !== null)
|
|
{
|
|
let nsel = sel+dir, n = this.getTotalItems();
|
|
if (nsel < 0)
|
|
nsel = 0;
|
|
if (nsel >= n)
|
|
nsel = n-1;
|
|
if (sel != nsel)
|
|
{
|
|
if (ev.shiftKey)
|
|
this.selectTo(nsel);
|
|
else
|
|
this.selectOne(nsel);
|
|
let pos = this.getItemOffset(nsel);
|
|
if (pos[0] + pos[1] > this.refs.scroll.scrollTop + this.refs.scroll.offsetHeight)
|
|
this.refs.scroll.scrollTop = pos[0] + pos[1] - this.refs.scroll.offsetHeight;
|
|
else if (pos[0] < this.refs.scroll.scrollTop + this.getScrollPaddingTop())
|
|
this.refs.scroll.scrollTop = pos[0] - this.getScrollPaddingTop();
|
|
ev.stopPropagation();
|
|
}
|
|
ev.preventDefault(); // prevent scroll
|
|
}
|
|
}
|
|
else if (ev.keyCode == 36) // home
|
|
{
|
|
if (ev.shiftKey)
|
|
{
|
|
this.selectTo(0);
|
|
this.refs.scroll.scrollTop = pos[0] - this.getScrollPaddingTop();
|
|
}
|
|
else
|
|
this.selectOne(0);
|
|
}
|
|
else if (ev.keyCode == 35) // end
|
|
{
|
|
let nsel = this.getTotalItems()-1;
|
|
if (ev.shiftKey)
|
|
{
|
|
this.selectTo(nsel);
|
|
let pos = this.getItemOffset(nsel);
|
|
this.refs.scroll.scrollTop = pos[0] + pos[1] - this.refs.scroll.offsetHeight;
|
|
}
|
|
else
|
|
this.selectOne(nsel);
|
|
}
|
|
}
|
|
|
|
selectTo(ns)
|
|
{
|
|
if (this.lastSel === undefined)
|
|
return this.selectOne(ns);
|
|
let sel = {};
|
|
let 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)
|
|
sel = { begin: this.lastSel, end: ns };
|
|
else
|
|
sel[ns] = true;
|
|
this.setState({ selected: sel });
|
|
this.curSel = ns;
|
|
if (this.onSelectCurrent)
|
|
this.onSelectCurrent(ns);
|
|
}
|
|
|
|
selectOne(ns)
|
|
{
|
|
let sel = {};
|
|
sel[ns] = true;
|
|
this.setState({ selected: sel });
|
|
this.lastSel = ns;
|
|
this.curSel = ns;
|
|
if (this.onSelectCurrent)
|
|
this.onSelectCurrent(ns);
|
|
}
|
|
|
|
onListItemClick = (ev) =>
|
|
{
|
|
let t = ev.target;
|
|
while (t && !t.getAttribute('data-i'))
|
|
t = t.parentNode;
|
|
if (t)
|
|
{
|
|
let ns = parseInt(t.getAttribute('data-i'));
|
|
if (ev.shiftKey)
|
|
this.selectTo(ns);
|
|
else if (ev.ctrlKey)
|
|
{
|
|
this.state.selected[ns] = true;
|
|
this.curSel = ns;
|
|
if (this.onSelectCurrent)
|
|
this.onSelectCurrent(ns);
|
|
this.lastSel = this.lastSel === undefined ? ns : this.lastSel;
|
|
this.setState({ selected: this.state.selected });
|
|
}
|
|
else
|
|
this.selectOne(ns);
|
|
}
|
|
}
|
|
}
|