2019-08-29 13:00:01 +00:00
|
|
|
import React from 'react'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import { handleAnyClick } from '../../utils/event';
|
|
|
|
|
|
|
|
import DropDownItem from '../drop-down-item'
|
|
|
|
import DropDown from '../drop-down'
|
|
|
|
|
|
|
|
class ContextMenu extends React.PureComponent {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
visible: false
|
|
|
|
};
|
|
|
|
|
2019-09-10 12:12:15 +00:00
|
|
|
if (!this.state.visible)
|
2019-08-29 13:00:01 +00:00
|
|
|
handleAnyClick(true, this.handleClick);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.container = document.getElementById(this.props.targetAreaId) || document;
|
|
|
|
|
|
|
|
this.container.addEventListener('contextmenu', this.handleContextMenu);
|
|
|
|
this.container.addEventListener('scroll', this.handleScroll);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.container.removeEventListener('contextmenu', this.handleContextMenu);
|
|
|
|
handleAnyClick(false, this.handleClick);
|
|
|
|
this.container.removeEventListener('scroll', this.handleScroll);
|
|
|
|
}
|
|
|
|
|
|
|
|
handleContextMenu = (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
this.handleClick(e);
|
|
|
|
|
|
|
|
this.setState({
|
|
|
|
visible: true
|
|
|
|
});
|
|
|
|
|
|
|
|
const menu = document.getElementById('contextMenu');
|
|
|
|
const bounds = this.container.getBoundingClientRect();
|
|
|
|
|
|
|
|
const clickX = e.clientX - bounds.left;
|
|
|
|
const clickY = e.clientY - bounds.top;
|
|
|
|
|
|
|
|
const screenW = this.container.offsetWidth;
|
|
|
|
const screenH = this.container.offsetHeight;
|
2019-09-10 12:12:15 +00:00
|
|
|
|
2019-08-29 13:00:01 +00:00
|
|
|
const rootW = menu.offsetWidth;
|
|
|
|
const rootH = menu.offsetHeight;
|
|
|
|
|
|
|
|
const right = (screenW - clickX) > rootW;
|
|
|
|
const left = !right;
|
|
|
|
const top = (screenH - clickY) > rootH;
|
|
|
|
const bottom = !top;
|
|
|
|
|
|
|
|
if (right) {
|
|
|
|
menu.style.left = `${clickX + 5}px`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (left) {
|
|
|
|
menu.style.left = `${clickX - rootW - 5}px`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (top) {
|
|
|
|
menu.style.top = `${clickY + 5}px`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bottom) {
|
|
|
|
menu.style.top = `${clickY - rootH - 5}px`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
handleClick = (e) => {
|
|
|
|
const { visible } = this.state;
|
|
|
|
const menu = document.getElementById('contextMenu');
|
|
|
|
const wasOutside = !(e.target.contains === menu);
|
|
|
|
|
|
|
|
if (wasOutside && visible)
|
|
|
|
this.setState({ visible: false });
|
|
|
|
}
|
|
|
|
|
|
|
|
handleScroll = () => {
|
|
|
|
const { visible } = this.state;
|
|
|
|
|
|
|
|
if (visible)
|
|
|
|
this.setState({ visible: false });
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { visible } = this.state;
|
|
|
|
const { options } = this.props;
|
|
|
|
|
|
|
|
return (visible && options || null) &&
|
|
|
|
<DropDown id="contextMenu" opened={true}>
|
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-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,
|
|
|
|
targetAreaId: PropTypes.string
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ContextMenu.defaultProps = {
|
2019-09-09 13:44:37 +00:00
|
|
|
options: []
|
2019-08-29 13:00:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export default ContextMenu;
|