2018-12-02 19:27:22 +03:00
|
|
|
import React from 'react';
|
|
|
|
|
|
|
|
export default class DropDownBase extends React.PureComponent
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
2018-12-02 19:27:22 +03:00
|
|
|
static instances = {};
|
|
|
|
static currentVisible = null;
|
2016-09-11 15:49:57 +03:00
|
|
|
|
2018-12-02 19:27:22 +03:00
|
|
|
state = { visible: false, top: 0, left: 0, calloutLeft: null, selectedItem: -1 };
|
|
|
|
|
|
|
|
componentDidMount()
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
if (!DropDownBase.setBodyListener)
|
|
|
|
{
|
|
|
|
window.addEventListener('click', DropDownBase.hideAll);
|
|
|
|
window.addEventListener('resize', DropDownBase.repositionCurrent);
|
|
|
|
DropDownBase.setBodyListener = true;
|
|
|
|
}
|
|
|
|
DropDownBase.instances[this.props.id] = this;
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static hideAll()
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
2019-05-14 15:49:20 +03:00
|
|
|
for (let i in DropDownBase.instances)
|
2016-09-11 15:49:57 +03:00
|
|
|
DropDownBase.instances[i].hide();
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static repositionCurrent()
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
if (DropDownBase.currentVisible)
|
|
|
|
DropDownBase.currentVisible[0].showAt(DropDownBase.currentVisible[1], DropDownBase.currentVisible[0].onClose);
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount()
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
delete DropDownBase.instances[this.props.id];
|
|
|
|
if (DropDownBase.currentVisible[0] == this)
|
|
|
|
DropDownBase.currentVisible = null;
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
onClick = (ev) =>
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
ev.stopPropagation();
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
isVisible = () =>
|
2016-10-01 23:59:02 +03:00
|
|
|
{
|
|
|
|
return this.state.visible;
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
hide = () =>
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
this.setState({ visible: false });
|
|
|
|
DropDownBase.currentVisible = null;
|
|
|
|
if (this.onClose)
|
|
|
|
{
|
|
|
|
this.onClose();
|
|
|
|
delete this.onClose;
|
|
|
|
}
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
showAt = (el, onClose) =>
|
2016-09-11 15:49:57 +03:00
|
|
|
{
|
|
|
|
if (this.onClose && this.onClose != onClose)
|
|
|
|
{
|
|
|
|
this.onClose();
|
|
|
|
delete this.onClose;
|
|
|
|
}
|
|
|
|
DropDownBase.currentVisible = [ this, el ];
|
2019-05-14 15:49:20 +03:00
|
|
|
let p = getOffset(el);
|
|
|
|
let left = p.left, top = p.top+el.offsetHeight, calloutLeft = null;
|
2016-09-11 15:49:57 +03:00
|
|
|
this.setState({ visible: true, top: top, left: left, selectedItem: -1 });
|
|
|
|
this.refs.dd.style.display = 'block';
|
|
|
|
if (this.props.window)
|
|
|
|
{
|
|
|
|
left = Math.round(p.left+el.offsetWidth/2-this.refs.dd.offsetWidth/2);
|
|
|
|
top = p.top+el.offsetHeight+3;
|
|
|
|
}
|
2019-05-14 15:49:20 +03:00
|
|
|
let ww = window.innerWidth || de.clientWidth || db.clientWidth;
|
|
|
|
let wh = window.innerHeight || de.clientHeight || db.clientHeight;
|
2016-09-11 15:49:57 +03:00
|
|
|
if (left + this.refs.dd.offsetWidth > ww)
|
|
|
|
{
|
|
|
|
left = ww-this.refs.dd.offsetWidth;
|
|
|
|
calloutLeft = Math.round(p.left+el.offsetWidth/2-left);
|
|
|
|
}
|
|
|
|
if (top + this.refs.dd.offsetHeight > wh)
|
|
|
|
top = wh-this.refs.dd.offsetHeight;
|
|
|
|
this.refs.dd.style.display = '';
|
|
|
|
this.setState({ visible: true, top: top, left: left, calloutLeft: calloutLeft });
|
|
|
|
this.refs.dd.focus();
|
|
|
|
this.onClose = onClose;
|
|
|
|
}
|
2018-12-02 19:27:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function getOffset(elem)
|
|
|
|
{
|
|
|
|
if (elem.getBoundingClientRect)
|
|
|
|
{
|
2019-05-14 15:49:20 +03:00
|
|
|
let box = elem.getBoundingClientRect();
|
|
|
|
let body = document.body;
|
|
|
|
let docElem = document.documentElement;
|
|
|
|
let scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop;
|
|
|
|
let scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft;
|
|
|
|
let clientTop = docElem.clientTop || body.clientTop || 0;
|
|
|
|
let clientLeft = docElem.clientLeft || body.clientLeft || 0;
|
|
|
|
let top = box.top + scrollTop - clientTop;
|
|
|
|
let left = box.left + scrollLeft - clientLeft;
|
2018-12-02 19:27:22 +03:00
|
|
|
return { top: Math.round(top), left: Math.round(left) };
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-14 15:49:20 +03:00
|
|
|
let top = 0, left = 0;
|
2019-05-20 00:27:28 +03:00
|
|
|
while (elem)
|
2018-12-02 19:27:22 +03:00
|
|
|
{
|
|
|
|
top = top + parseInt(elem.offsetTop);
|
|
|
|
left = left + parseInt(elem.offsetLeft);
|
|
|
|
elem = elem.offsetParent;
|
|
|
|
}
|
|
|
|
return { top: top, left: left };
|
|
|
|
}
|
|
|
|
}
|