1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/*
* This file is part of Cockpit.
*
* Copyright (C) 2019 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import PropTypes from "prop-types";
import { Menu, MenuContent } from "@patternfly/react-core/dist/esm/components/Menu";
import "context-menu.scss";
/*
* A context menu component
*
* It requires two properties:
* - parentId, area in which it listens to left button click
* - children, a MenuList to be rendered in the context menu
*/
export const ContextMenu = ({ parentId, children }) => {
const [visible, setVisible] = React.useState(false);
const [event, setEvent] = React.useState(null);
const root = React.useRef(null);
React.useEffect(() => {
const _handleContextMenu = (event) => {
event.preventDefault();
setVisible(true);
setEvent(event);
};
const _handleClick = (event) => {
if (event && event.button === 0) {
const wasOutside = !(event.target.contains === root.current);
if (wasOutside)
setVisible(false);
}
};
const parent = document.getElementById(parentId);
parent.addEventListener('contextmenu', _handleContextMenu);
document.addEventListener('click', _handleClick);
return () => {
parent.removeEventListener('contextmenu', _handleContextMenu);
document.removeEventListener('click', _handleClick);
};
}, [parentId]);
React.useEffect(() => {
if (!event)
return;
const clickX = event.clientX;
const clickY = event.clientY;
const screenW = window.innerWidth;
const screenH = window.innerHeight;
const rootW = root.current.offsetWidth;
const rootH = root.current.offsetHeight;
const right = (screenW - clickX) > rootW;
const left = !right;
const top = (screenH - clickY) > rootH;
const bottom = !top;
if (right) {
root.current.style.left = `${clickX + 5}px`;
}
if (left) {
root.current.style.left = `${clickX - rootW - 5}px`;
}
if (top) {
root.current.style.top = `${clickY + 5}px`;
}
if (bottom) {
root.current.style.top = `${clickY - rootH - 5}px`;
}
}, [event]);
return visible &&
<Menu ref={root} className="contextMenu">
<MenuContent ref={root}>
{children}
</MenuContent>
</Menu>;
};
ContextMenu.propTypes = {
parentId: PropTypes.string.isRequired,
children: PropTypes.any
};
|