diff --git a/__tests__/src/components/Window.test.js b/__tests__/src/components/Window.test.js index 2f7928581db4792ae2a82d66f405bd12a38c1b6e..301b75b7852431700caa2758cd6a6463c80cf1a1 100644 --- a/__tests__/src/components/Window.test.js +++ b/__tests__/src/components/Window.test.js @@ -5,8 +5,14 @@ import WindowTopBar from '../../../src/containers/WindowTopBar'; import WindowMiddleContent from '../../../src/containers/WindowMiddleContent'; /** create wrapper */ -function createWrapper(window) { - return shallow(<Window window={window} />); +function createWrapper(props, context) { + return shallow( + <Window + window={window} + {...props} + />, + { context }, + ); } describe('Window', () => { @@ -17,19 +23,27 @@ describe('Window', () => { expect(wrapper.find('.mirador-window')).toHaveLength(0); }); it('should render outer element', () => { - wrapper = createWrapper(window); + wrapper = createWrapper({ window }); expect(wrapper.find('.mirador-window')).toHaveLength(1); }); it('should render <WindowTopBar>', () => { - wrapper = createWrapper(window); + wrapper = createWrapper({ window }); expect(wrapper.find(WindowTopBar)).toHaveLength(1); }); it('should render <WindowMiddleContent>', () => { - wrapper = createWrapper(window); + wrapper = createWrapper({ window }); expect(wrapper.find(WindowMiddleContent)).toHaveLength(1); }); it('should render bottom companions window areas', () => { - wrapper = createWrapper(window); + wrapper = createWrapper({ window }); expect(wrapper.find('.mirador-companion-bottom')).toHaveLength(1); }); + describe('when workspaceType is mosaic', () => { + it('calls the context mosaicWindowActions connectDragSource method to make WindowTopBar draggable', () => { + const connectDragSource = jest.fn(component => component); + wrapper = createWrapper({ window, workspaceType: 'mosaic' }, { mosaicWindowActions: { connectDragSource } }); + expect(wrapper.find(WindowTopBar)).toHaveLength(1); + expect(connectDragSource).toHaveBeenCalled(); + }); + }); }); diff --git a/__tests__/src/components/WorkspaceMosaic.test.js b/__tests__/src/components/WorkspaceMosaic.test.js index 01bfd5a2557b6122c2374dfe1d1684de91c20e7e..3bab72ceec78862efd2f9d439a5b51587e28ea52 100644 --- a/__tests__/src/components/WorkspaceMosaic.test.js +++ b/__tests__/src/components/WorkspaceMosaic.test.js @@ -50,7 +50,21 @@ describe('WorkspaceMosaic', () => { }); describe('tileRenderer', () => { it('when window is available', () => { - expect(wrapper.instance().tileRenderer('1')).not.toBeNull(); + const renderedTile = wrapper.instance().tileRenderer('1', 'foo'); + expect(renderedTile).not.toBeNull(); + expect(shallow(renderedTile).find('DropTarget(DragSource(InternalMosaicWindow))').length).toEqual(1); + expect(shallow(renderedTile).props()).toEqual(expect.objectContaining({ + toolbarControls: [], + additionalControls: [], + path: 'foo', + })); + expect(shallow(shallow(renderedTile).props().renderPreview()).matchesElement( + <div className="mosaic-preview"> + <div className="mosaic-window-body"> + <h4>previewWindowTitle</h4> + </div> + </div>, + )).toBe(true); }); it('when window is not available', () => { expect(wrapper.instance().tileRenderer('bar')).toBeNull(); diff --git a/locales/de/translation.json b/locales/de/translation.json index 48e789a857c4ada389ed5c596513cfb618828063..208514987b844e6593451530ec284eead49e4895 100644 --- a/locales/de/translation.json +++ b/locales/de/translation.json @@ -32,6 +32,7 @@ "openWindows": "Fenster öffnen", "openInCompanionWindow": "In Hilfsfenster öffnen", "position": "Position", + "previewWindowTitle": "Mirador", "right": "Rechts", "single": "Einzeln", "settings": "Einstellungen", diff --git a/locales/en/translation.json b/locales/en/translation.json index 5320a8eaa8ba579b08632f6e8930d74cdb187b2b..a7d13c7ddd8cd8c9c9b7909167a047b92e83c5cc 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -34,6 +34,7 @@ "openWindows": "Open windows", "openInCompanionWindow": "Open in companion window", "position": "Position", + "previewWindowTitle": "Mirador", "right": "Right", "single": "Single", "settings": "Settings", diff --git a/package.json b/package.json index 2397564365517a48e3fa438d9ebda535c185f98b..2e30890ca30358fee9349ff9d5229dff6f098b93 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "react-dom": "^16.8.3", "react-fullscreen-crossbrowser": "^1.0.9", "react-i18next": "^10.2.0", - "react-mosaic-component": "^2.0.2", + "react-mosaic-component": "^2.1.0", "react-placeholder": "^3.0.1", "react-redux": "^6.0.0", "react-virtualized": "^9.21.0", diff --git a/src/components/Window.js b/src/components/Window.js index d22e44b5bb7b5e41db47568792ea54f823373db9..8d5fe12de48196a276483f78987511664669c497 100644 --- a/src/components/Window.js +++ b/src/components/Window.js @@ -10,19 +10,36 @@ import ThumbnailNavigation from '../containers/ThumbnailNavigation'; * @param {object} window */ export class Window extends Component { + /** + * wrappedTopBar - will conditionally wrap a WindowTopBar for needed + * additional functionality based on workspace type + */ + wrappedTopBar() { + const { manifest, window, workspaceType } = this.props; + const { mosaicWindowActions } = this.context; + const topBar = ( + <div> + <WindowTopBar + windowId={window.id} + manifest={manifest} + /> + </div> + ); + if (workspaceType !== 'mosaic') return topBar; + return mosaicWindowActions.connectDragSource( + topBar, + ); + } + /** * Renders things */ render() { const { manifest, window } = this.props; if (!window) return <></>; - return ( <div id={window.id} className={ns('window')}> - <WindowTopBar - windowId={window.id} - manifest={manifest} - /> + {this.wrappedTopBar()} <WindowMiddleContent window={window} manifest={manifest} @@ -39,12 +56,21 @@ export class Window extends Component { } } +Window.contextTypes = { + mosaicWindowActions: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.object, + ]), +}; + Window.propTypes = { window: PropTypes.object, // eslint-disable-line react/forbid-prop-types manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types + workspaceType: PropTypes.string, }; Window.defaultProps = { window: null, manifest: null, + workspaceType: null, }; diff --git a/src/components/WorkspaceMosaic.js b/src/components/WorkspaceMosaic.js index 629081a2cfbc29f794c069ed448b10d47f4343da..a5e10faaa743593d95745db5551b5fb6b680023d 100644 --- a/src/components/WorkspaceMosaic.js +++ b/src/components/WorkspaceMosaic.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Mosaic, getLeaves, createBalancedTreeFromLeaves, + Mosaic, MosaicWindow, getLeaves, createBalancedTreeFromLeaves, } from 'react-mosaic-component'; import 'react-mosaic-component/react-mosaic-component.css'; import Window from '../containers/Window'; @@ -65,14 +65,28 @@ export class WorkspaceMosaic extends React.Component { * Render a tile (Window) in the Mosaic. */ tileRenderer(id, path) { - const { windows } = this.props; + const { windows, t } = this.props; const window = windows[id]; if (!window) return null; return ( - <Window - key={window.id} - window={window} - /> + <MosaicWindow + toolbarControls={[]} + additionalControls={[]} + path={path} + windowId={window.id} + renderPreview={() => ( + <div className="mosaic-preview"> + <div className="mosaic-window-body"> + <h4>{t('previewWindowTitle')}</h4> + </div> + </div> + )} + > + <Window + key={window.id} + window={window} + /> + </MosaicWindow> ); } @@ -101,7 +115,12 @@ export class WorkspaceMosaic extends React.Component { } WorkspaceMosaic.propTypes = { + t: PropTypes.func, updateWorkspaceMosaicLayout: PropTypes.func.isRequired, windows: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types workspace: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types }; + +WorkspaceMosaic.defaultProps = { + t: key => key, +}; diff --git a/src/containers/Window.js b/src/containers/Window.js index c0cbb4c5328fefd38855e9c38b7578ea13f7a532..a3e940cf00ed0ac34f67a9c8f9017c1be59d0a59 100644 --- a/src/containers/Window.js +++ b/src/containers/Window.js @@ -7,9 +7,10 @@ import { Window } from '../components/Window'; * @memberof Window * @private */ -const mapStateToProps = ({ manifests, windows }, props) => ({ +const mapStateToProps = ({ manifests, windows, config }, props) => ({ manifest: manifests[props.window.manifestId], window: windows[props.window.id], + workspaceType: config.workspace.type, }); const enhance = compose( diff --git a/src/containers/WorkspaceMosaic.js b/src/containers/WorkspaceMosaic.js index 7a1891a480c396c7f391573156678c2ee25cd3d8..092510e8a56f964c6b3b116a1533ec7ecda8dd02 100644 --- a/src/containers/WorkspaceMosaic.js +++ b/src/containers/WorkspaceMosaic.js @@ -1,5 +1,6 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; +import { withTranslation } from 'react-i18next'; import * as actions from '../state/actions'; import { WorkspaceMosaic } from '../components/WorkspaceMosaic'; @@ -23,6 +24,7 @@ const mapStateToProps = state => ( const mapDispatchToProps = { updateWorkspaceMosaicLayout: actions.updateWorkspaceMosaicLayout }; const enhance = compose( + withTranslation(), connect(mapStateToProps, mapDispatchToProps), // further HOC go here ); diff --git a/src/styles/index.scss b/src/styles/index.scss index e6d2633702fb71193ed960619cc3827f5e55cba5..60c03c799e62218a620bcd7e758537546a9f7101 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -5,6 +5,16 @@ height: 100%; position: relative; width: 100%; + + .mosaic-window-toolbar { + display: none; + } + + .mosaic-window-body { + .mirador-window-top-bar { + cursor: move; + } + } } &-workspace {