From ca4fef2db0fc71659a5d7f1e08506f5a64dd5387 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 5 May 2018 14:25:05 -0700 Subject: [PATCH] Supprt right-click context menu --- js/components/App.js | 6 +- js/components/ContextMenu.js | 70 +----------------- js/components/ContextMenuTarget.js | 71 +++++++++++++++++++ js/components/ContextMenuWrapper.js | 64 +++++++++++++++++ .../EqualizerWindow/PresetsContextMenu.js | 3 +- js/components/MainWindow/MainContextMenu.js | 11 +-- js/components/MainWindow/index.js | 10 ++- js/components/PlaylistWindow/MiscMenu.js | 3 +- 8 files changed, 157 insertions(+), 81 deletions(-) create mode 100644 js/components/ContextMenuTarget.js create mode 100644 js/components/ContextMenuWrapper.js diff --git a/js/components/App.js b/js/components/App.js index 5ae96674..5a08028c 100644 --- a/js/components/App.js +++ b/js/components/App.js @@ -1,6 +1,8 @@ import React from "react"; import PropTypes from "prop-types"; import { connect } from "react-redux"; +import ContextMenuWrapper from "./ContextMenuWrapper"; +import MainContextMenu from "./MainWindow/MainContextMenu"; import WindowManager from "./WindowManager"; import MainWindow from "./MainWindow"; import PlaylistWindow from "./PlaylistWindow"; @@ -51,7 +53,9 @@ const App = ({ return (
- + + +
); }; diff --git a/js/components/ContextMenu.js b/js/components/ContextMenu.js index 5dc67f93..d837fd7b 100644 --- a/js/components/ContextMenu.js +++ b/js/components/ContextMenu.js @@ -66,7 +66,7 @@ Node.propTypes = { label: PropTypes.string.isRequired }; -class ContextMenu extends React.Component { +export class ContextMenu extends React.Component { render() { const { children, @@ -87,71 +87,3 @@ class ContextMenu extends React.Component { ); } } - -export class ContextMenuTarget extends React.Component { - constructor(props) { - super(props); - this.state = { selected: false }; - this._handleHandleClick = this._handleHandleClick.bind(this); - this._handleGlobalClick = this._handleGlobalClick.bind(this); - } - - componentDidMount() { - document.addEventListener("click", this._handleGlobalClick); - } - - componentWillUnmount() { - document.removeEventListener("click", this._handleGlobalClick); - } - - _handleHandleClick() { - this.setState({ selected: !this.state.selected }); - } - - _handleGlobalClick(e) { - if ( - this.state.selected && - // Not sure how, but it's possible for this to get called when handleNode is null/undefined. - // https://sentry.io/share/issue/2066cd79f21e4f279791319f4d2ea35d/ - this.handleNode && - !this.handleNode.contains(e.target) - ) { - this.setState({ selected: false }); - } - } - - render() { - const { handle, children, top, bottom, ...passThroughProps } = this.props; - const rect = this.handleNode - ? this.handleNode.getBoundingClientRect() - : { top: 0, left: 0 }; - return ( -
-
(this.handleNode = node)} - onClick={this._handleHandleClick} - > - {handle} -
- - {children} - -
- ); - } -} - -ContextMenuTarget.propTypes = { - children: PropTypes.any.isRequired, - handle: PropTypes.any.isRequired, - top: PropTypes.bool, - bottom: PropTypes.bool -}; diff --git a/js/components/ContextMenuTarget.js b/js/components/ContextMenuTarget.js new file mode 100644 index 00000000..6851f5fd --- /dev/null +++ b/js/components/ContextMenuTarget.js @@ -0,0 +1,71 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { ContextMenu } from "./ContextMenu"; + +export default class ContextMenuTarget extends React.Component { + constructor(props) { + super(props); + this.state = { selected: false }; + this._handleHandleClick = this._handleHandleClick.bind(this); + this._handleGlobalClick = this._handleGlobalClick.bind(this); + } + + componentDidMount() { + document.addEventListener("click", this._handleGlobalClick); + } + + componentWillUnmount() { + document.removeEventListener("click", this._handleGlobalClick); + } + + _handleHandleClick() { + this.setState({ selected: !this.state.selected }); + } + + _handleGlobalClick(e) { + if ( + this.state.selected && + // Not sure how, but it's possible for this to get called when handleNode is null/undefined. + // https://sentry.io/share/issue/2066cd79f21e4f279791319f4d2ea35d/ + this.handleNode && + !this.handleNode.contains(e.target) + ) { + this.setState({ selected: false }); + } + } + + render() { + const { handle, children, top, bottom, ...passThroughProps } = this.props; + const rect = this.handleNode + ? this.handleNode.getBoundingClientRect() + : { top: 0, left: 0 }; + return ( +
+
(this.handleNode = node)} + onClick={this._handleHandleClick} + > + {handle} +
+ + {children} + +
+ ); + } +} + +ContextMenuTarget.propTypes = { + children: PropTypes.any.isRequired, + handle: PropTypes.any.isRequired, + top: PropTypes.bool, + bottom: PropTypes.bool +}; diff --git a/js/components/ContextMenuWrapper.js b/js/components/ContextMenuWrapper.js new file mode 100644 index 00000000..8dab1ef9 --- /dev/null +++ b/js/components/ContextMenuWrapper.js @@ -0,0 +1,64 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { ContextMenu } from "./ContextMenu"; + +export default class ContextMenuWraper extends React.Component { + constructor(props) { + super(props); + this.state = { + selected: false, + offsetTop: null, + offsetLeft: null + }; + this._handleRightClick = this._handleRightClick.bind(this); + this._handleGlobalClick = this._handleGlobalClick.bind(this); + } + + _handleGlobalClick() { + this.setState({ + selected: false, + offsetTop: null, + offsetLeft: null + }); + document.removeEventListener("click", this._handleGlobalClick); + } + + _handleRightClick(e) { + const { pageX, pageY } = e; + this.setState({ + selected: true, + offsetTop: pageY, + offsetLeft: pageX + }); + // Even if you right click multiple times before closeing, + // we should only end up with one global listener. + document.addEventListener("click", this._handleGlobalClick); + e.preventDefault(); + e.stopPropagation(); + } + + render() { + const { children, Contents, ...passThroughProps } = this.props; + return ( +
+ + + + {children} +
+ ); + } +} + +ContextMenuWraper.propTypes = { + children: PropTypes.any.isRequired, + Contents: PropTypes.any.isRequired +}; diff --git a/js/components/EqualizerWindow/PresetsContextMenu.js b/js/components/EqualizerWindow/PresetsContextMenu.js index b866cc3b..6fe7471c 100644 --- a/js/components/EqualizerWindow/PresetsContextMenu.js +++ b/js/components/EqualizerWindow/PresetsContextMenu.js @@ -1,7 +1,8 @@ import React from "react"; import { connect } from "react-redux"; import { openEqfFileDialog, downloadPreset } from "../../actionCreators"; -import { ContextMenuTarget, Node } from "../ContextMenu"; +import { Node } from "../ContextMenu"; +import ContextMenuTarget from "../ContextMenuTarget"; const PresetsContextMenu = props => ( }> diff --git a/js/components/MainWindow/MainContextMenu.js b/js/components/MainWindow/MainContextMenu.js index 4b0297cb..5b66cd3d 100644 --- a/js/components/MainWindow/MainContextMenu.js +++ b/js/components/MainWindow/MainContextMenu.js @@ -1,6 +1,5 @@ import React from "react"; import { connect } from "react-redux"; -import ClickedDiv from "../ClickedDiv"; import { close, setSkinFromUrl, @@ -16,14 +15,10 @@ import { } from "../../actionTypes"; import { getGenWindows } from "../../selectors"; import { LOAD_STYLE } from "../../constants"; -import { ContextMenuTarget, Hr, Node, Parent, LinkNode } from "../ContextMenu"; +import { Hr, Node, Parent, LinkNode } from "../ContextMenu"; const MainContextMenu = props => ( - } - > + (
-
+ ); const mapStateToProps = state => ({ diff --git a/js/components/MainWindow/index.js b/js/components/MainWindow/index.js index 0ecc7962..958467b4 100644 --- a/js/components/MainWindow/index.js +++ b/js/components/MainWindow/index.js @@ -14,6 +14,8 @@ import DropTarget from "../DropTarget"; import MiniTime from "../MiniTime"; import { SET_FOCUSED_WINDOW } from "../../actionTypes"; +import ClickedDiv from "../ClickedDiv"; +import ContextMenuTarget from "../ContextMenuTarget"; import ActionButtons from "./ActionButtons"; import MainBalance from "./MainBalance"; import Close from "./Close"; @@ -90,7 +92,13 @@ export class MainWindow extends React.Component { className="selected title-bard draggable" onDoubleClick={this.props.toggleMainWindowShadeMode} > - + } + > + + {mainShade && } diff --git a/js/components/PlaylistWindow/MiscMenu.js b/js/components/PlaylistWindow/MiscMenu.js index 3242db92..cde4f97a 100644 --- a/js/components/PlaylistWindow/MiscMenu.js +++ b/js/components/PlaylistWindow/MiscMenu.js @@ -7,7 +7,8 @@ import { downloadHtmlPlaylist } from "../../actionCreators"; -import { ContextMenuTarget, Hr, Node } from "../ContextMenu"; +import { Hr, Node } from "../ContextMenu"; +import ContextMenuTarget from "../ContextMenuTarget"; import PlaylistMenu from "./PlaylistMenu"; /* eslint-disable no-alert */