likeopera-frontend/ListWithSelection.js

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);
}
}
}