From 7567c199916ae2f6af8d73bca580ffb68008306c Mon Sep 17 00:00:00 2001 From: Chris Beer <cabeer@stanford.edu> Date: Wed, 30 Jan 2019 13:49:47 -0800 Subject: [PATCH] Copy the workspace menu + button as a menu + button for the window --- .../src/components/WindowTopMenu.test.js | 17 ++++ .../components/WindowTopMenuButton.test.js | 20 ++++ src/components/WindowTopBar.js | 2 + src/components/WindowTopMenu.js | 59 ++++++++++++ src/components/WindowTopMenuButton.js | 92 +++++++++++++++++++ src/containers/WindowTopMenu.js | 4 + 6 files changed, 194 insertions(+) create mode 100644 __tests__/src/components/WindowTopMenu.test.js create mode 100644 __tests__/src/components/WindowTopMenuButton.test.js create mode 100644 src/components/WindowTopMenu.js create mode 100644 src/components/WindowTopMenuButton.js create mode 100644 src/containers/WindowTopMenu.js diff --git a/__tests__/src/components/WindowTopMenu.test.js b/__tests__/src/components/WindowTopMenu.test.js new file mode 100644 index 000000000..47851603c --- /dev/null +++ b/__tests__/src/components/WindowTopMenu.test.js @@ -0,0 +1,17 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import WindowTopMenu from '../../../src/components/WindowTopMenu'; + +describe('WindowTopMenu', () => { + let wrapper; + let handleClose; + beforeEach(() => { + handleClose = jest.fn(); + wrapper = shallow(<WindowTopMenu windowId="xyz" handleClose={handleClose} />).dive(); + }); + + it('renders without an error', () => { + expect(wrapper.find('WithStyles(Menu)').length).toBe(1); + expect(wrapper.find('Connect(WindowThumbnailSettings)').length).toBe(1); + }); +}); diff --git a/__tests__/src/components/WindowTopMenuButton.test.js b/__tests__/src/components/WindowTopMenuButton.test.js new file mode 100644 index 000000000..c016c58da --- /dev/null +++ b/__tests__/src/components/WindowTopMenuButton.test.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import WindowTopMenuButton from '../../../src/components/WindowTopMenuButton'; + +describe('WindowTopMenuButton', () => { + let wrapper; + beforeEach(() => { + wrapper = shallow( + <WindowTopMenuButton classes={{}} windowId="xyz" />, + ).dive(); + }); + + it('renders without an error', () => { + expect(wrapper.find('WithStyles(IconButton)').length).toBe(1); + }); + it('when clicked, updates the state', () => { + wrapper.find('WithStyles(IconButton)').simulate('click', { currentTarget: 'x' }); + expect(wrapper.find('Connect(miradorWithPlugins(WithStyles(WindowTopMenu)))').props().anchorEl).toBe('x'); + }); +}); diff --git a/src/components/WindowTopBar.js b/src/components/WindowTopBar.js index bf5e05275..a5f61fdb2 100644 --- a/src/components/WindowTopBar.js +++ b/src/components/WindowTopBar.js @@ -7,6 +7,7 @@ import IconButton from '@material-ui/core/IconButton'; import MenuIcon from '@material-ui/icons/Menu'; import Toolbar from '@material-ui/core/Toolbar'; import classNames from 'classnames'; +import WindowTopMenuButton from './WindowTopMenuButton'; import WindowTopBarButtons from '../containers/WindowTopBarButtons'; import ns from '../config/css-ns'; @@ -48,6 +49,7 @@ class WindowTopBar extends Component { {this.titleContent()} </Typography> <WindowTopBarButtons windowId={windowId} /> + <WindowTopMenuButton className={ns('window-menu-btn')} windowId={windowId} /> <Button color="inherit" className={ns('window-close')} aria-label="Close Window" onClick={removeWindow}>×</Button> </Toolbar> ); diff --git a/src/components/WindowTopMenu.js b/src/components/WindowTopMenu.js new file mode 100644 index 000000000..15aa2c458 --- /dev/null +++ b/src/components/WindowTopMenu.js @@ -0,0 +1,59 @@ +import React, { Component } from 'react'; +import { compose } from 'redux'; +import Menu from '@material-ui/core/Menu'; +import Divider from '@material-ui/core/Divider'; +import { withStyles } from '@material-ui/core/styles'; +import PropTypes from 'prop-types'; + +/** + */ +class WindowTopMenu extends Component { + /** + * constructor - + */ + constructor(props) { + super(props); + this.state = { + }; + } + + /** + * render + * @return + */ + render() { + const { handleClose, anchorEl, windowId } = this.props; + // const {} = this.state; + + return ( + <> + <Menu id={`window-menu_${windowId}`} anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}> + <Divider /> + </Menu> + </> + ); + } +} + +WindowTopMenu.propTypes = { + windowId: PropTypes.string.isRequired, + handleClose: PropTypes.func.isRequired, + anchorEl: PropTypes.object, // eslint-disable-line react/forbid-prop-types +}; + +WindowTopMenu.defaultProps = { + anchorEl: null, +}; + +/** + * @private + */ +const styles = theme => ({ +}); + +const enhance = compose( + withStyles(styles), + // further HOC go here +); + +export default enhance(WindowTopMenu); diff --git a/src/components/WindowTopMenuButton.js b/src/components/WindowTopMenuButton.js new file mode 100644 index 000000000..a8b66b249 --- /dev/null +++ b/src/components/WindowTopMenuButton.js @@ -0,0 +1,92 @@ +import React, { Component } from 'react'; +import { compose } from 'redux'; +import IconButton from '@material-ui/core/IconButton'; +import MoreVertIcon from '@material-ui/icons/MoreVert'; +import { withStyles } from '@material-ui/core/styles'; +import PropTypes from 'prop-types'; +import WindowTopMenu from '../containers/WindowTopMenu'; + +/** + */ +class WindowTopMenuButton extends Component { + /** + * constructor - + */ + constructor(props) { + super(props); + this.state = { + anchorEl: null, + }; + this.handleMenuClick = this.handleMenuClick.bind(this); + this.handleMenuClose = this.handleMenuClose.bind(this); + } + + /** + * @private + */ + handleMenuClick(event) { + this.setState({ + anchorEl: event.currentTarget, + }); + } + + /** + * @private + */ + handleMenuClose() { + this.setState({ + anchorEl: null, + }); + } + + /** + * render + * @return + */ + render() { + const { classes, windowId } = this.props; + const { anchorEl } = this.state; + + return ( + <> + <IconButton + color="primary" + aria-label="Menu" + className={classes.ctrlBtn} + aria-haspopup="true" + onClick={this.handleMenuClick} + aria-owns={anchorEl ? `window-menu_${windowId}` : undefined} + > + <MoreVertIcon /> + </IconButton> + <WindowTopMenu + windowId={windowId} + anchorEl={anchorEl} + handleClose={this.handleMenuClose} + /> + </> + ); + } +} + +WindowTopMenuButton.propTypes = { + windowId: PropTypes.string.isRequired, + classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types +}; + +/** + * @private + */ +const styles = theme => ({ + ctrlBtn: { + margin: theme.spacing.unit, + }, +}); + + +const enhance = compose( + withStyles(styles), + // further HOC go here +); + +export default enhance(WindowTopMenuButton); diff --git a/src/containers/WindowTopMenu.js b/src/containers/WindowTopMenu.js new file mode 100644 index 000000000..cd163f2f5 --- /dev/null +++ b/src/containers/WindowTopMenu.js @@ -0,0 +1,4 @@ +import miradorWithPlugins from '../lib/miradorWithPlugins'; +import WindowTopMenu from '../components/WindowTopMenu'; + +export default miradorWithPlugins(WindowTopMenu); -- GitLab