2019-08-29 13:00:01 +00:00
|
|
|
import React from 'react'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import DropDownItem from '../drop-down-item'
|
|
|
|
import DropDown from '../drop-down'
|
|
|
|
|
|
|
|
class ContextMenu extends React.PureComponent {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
visible: false
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.container = document.getElementById(this.props.targetAreaId) || document;
|
|
|
|
|
|
|
|
this.container.addEventListener('contextmenu', this.handleContextMenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.container.removeEventListener('contextmenu', this.handleContextMenu);
|
|
|
|
}
|
|
|
|
|
2019-11-11 11:55:05 +00:00
|
|
|
moveMenu = e => {
|
2019-11-27 13:06:48 +00:00
|
|
|
const menu = document.getElementById(this.props.id);
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2020-01-20 12:32:19 +00:00
|
|
|
//if (!menu) return;
|
|
|
|
|
|
|
|
const bounds = (this.container !== document) && this.container.getBoundingClientRect();
|
2019-08-29 13:00:01 +00:00
|
|
|
const clickX = e.clientX - bounds.left;
|
|
|
|
const clickY = e.clientY - bounds.top;
|
2020-01-20 12:32:19 +00:00
|
|
|
const containerWidth = this.container.offsetWidth;
|
|
|
|
const containerHeight = this.container.offsetHeight;
|
|
|
|
const menuWidth = menu && menu.offsetWidth;
|
|
|
|
const menuHeight = menu && menu.offsetHeight;
|
|
|
|
const right = (containerWidth - clickX) > menuWidth;
|
2019-08-29 13:00:01 +00:00
|
|
|
const left = !right;
|
2020-01-20 12:32:19 +00:00
|
|
|
const bottom = (containerHeight - clickY) < menuHeight && clickY > menuHeight;
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2019-11-11 11:55:05 +00:00
|
|
|
let newTop = `0px`;
|
|
|
|
let newLeft = `0px`;
|
|
|
|
|
2020-01-20 12:32:19 +00:00
|
|
|
newLeft = left ? `${clickX - menuWidth - 8}px` : `${clickX + 8}px`;
|
|
|
|
newTop = bottom ? `${clickY - menuHeight}px` : `${clickY}px`;
|
2019-11-11 11:55:05 +00:00
|
|
|
|
2020-01-20 12:32:19 +00:00
|
|
|
if(menu) {
|
|
|
|
menu.style.top = newTop;
|
|
|
|
menu.style.left = newLeft;
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-11 11:55:05 +00:00
|
|
|
handleContextMenu = (e) => {
|
|
|
|
if (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
this.handleClick(e);
|
|
|
|
}
|
2020-01-20 12:32:19 +00:00
|
|
|
|
2019-11-11 11:55:05 +00:00
|
|
|
this.setState({
|
|
|
|
visible: true
|
|
|
|
});
|
|
|
|
|
|
|
|
if (e) this.moveMenu(e);
|
|
|
|
}
|
|
|
|
|
2019-08-29 13:00:01 +00:00
|
|
|
handleClick = (e) => {
|
|
|
|
const { visible } = this.state;
|
2019-11-27 13:06:48 +00:00
|
|
|
const menu = document.getElementById(this.props.id);
|
2019-11-11 11:55:05 +00:00
|
|
|
const wasOutside = e.target ? !(e.target.contains === menu) : true;
|
2019-08-29 13:00:01 +00:00
|
|
|
|
|
|
|
if (wasOutside && visible)
|
|
|
|
this.setState({ visible: false });
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { visible } = this.state;
|
2019-11-27 13:06:48 +00:00
|
|
|
const { options, id, className, style } = this.props;
|
2019-08-29 13:00:01 +00:00
|
|
|
|
2019-11-27 13:06:48 +00:00
|
|
|
return (visible && options || null) && (
|
2020-01-20 12:32:19 +00:00
|
|
|
<DropDown
|
|
|
|
id={id}
|
|
|
|
className={className}
|
|
|
|
style={style}
|
|
|
|
open={true}
|
|
|
|
clickOutsideAction={this.handleClick}
|
|
|
|
>
|
2019-09-10 12:12:15 +00:00
|
|
|
{options.map((item) => {
|
|
|
|
if (item && item.key !== undefined) {
|
|
|
|
return <DropDownItem key={item.key} {...item} />
|
|
|
|
}
|
|
|
|
})}
|
2019-08-29 13:00:01 +00:00
|
|
|
</DropDown>
|
2019-11-27 13:06:48 +00:00
|
|
|
)
|
2019-09-09 13:44:37 +00:00
|
|
|
}
|
2019-08-29 13:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ContextMenu.propTypes = {
|
2019-09-09 13:44:37 +00:00
|
|
|
options: PropTypes.array,
|
2019-11-27 13:06:48 +00:00
|
|
|
targetAreaId: PropTypes.string,
|
|
|
|
className: PropTypes.string,
|
|
|
|
id: PropTypes.string,
|
|
|
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ContextMenu.defaultProps = {
|
2019-11-27 13:06:48 +00:00
|
|
|
options: [],
|
|
|
|
id: "contextMenu"
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export default ContextMenu;
|