diff --git a/.eslintrc b/.eslintrc index f6de202..b2f6c0f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -26,6 +26,6 @@ } }], "react/prefer-stateless-function": "off", - "react/destructuring-assignment": [false, "never"] + "react/destructuring-assignment": [0, "never"] } } diff --git a/.travis.yml b/.travis.yml index 75578a0..42c6852 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ before_script: - cd packages/mirador3-core - npm install - cd ../mirador3-common - npm install - - cd ../mirador3-app + - npm install + - cd ../mirador3-app-base - npm install - cd ../.. - lerna run build diff --git a/minimal_redux_poc/__tests__/integration/mirador/window_actions.test.js b/minimal_redux_poc/__tests__/integration/mirador/window_actions.test.js new file mode 100644 index 0000000..e16d8b4 --- /dev/null +++ b/minimal_redux_poc/__tests__/integration/mirador/window_actions.test.js @@ -0,0 +1,15 @@ +describe('Window actions', () => { + beforeAll(async () => { + await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/'); + }); + it('opens a window and closes it', async () => { + await expect(page).toFill('#manifestURL', 'https://purl.stanford.edu/sn904cj3429/iiif/manifest'); + await expect(page).toClick('#fetchBtn'); + // TODO: Refactor the app so we get rid of the wait + await page.waitFor(1000); + await expect(page).toClick('li button'); + await expect(page).toMatchElement('.mirador-window'); + await expect(page).toClick('.mirador-window-close'); + await expect(page).not.toMatchElement('.mirador-window'); + }); +}); diff --git a/minimal_redux_poc/package-lock.json b/minimal_redux_poc/package-lock.json index de06dea..450eea3 100644 --- a/minimal_redux_poc/package-lock.json +++ b/minimal_redux_poc/package-lock.json @@ -6670,9 +6670,9 @@ } }, "merge": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", - "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", "dev": true }, "merge-stream": { diff --git a/minimal_redux_poc/src/components/Window.js b/minimal_redux_poc/src/components/Window.js new file mode 100644 index 0000000..df51142 --- /dev/null +++ b/minimal_redux_poc/src/components/Window.js @@ -0,0 +1,120 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import fetch from 'node-fetch'; +import OpenSeaDragon from 'openseadragon'; +import ns from '../config/css-ns'; +import WindowTopBar from './WindowTopBar'; + +/** + * Represents a Window in the mirador workspace + * @param {object} window + */ +class Window extends Component { + /** + * @param {Object} props [description] + */ + constructor(props) { + super(props); + + this.miradorInstanceRef = React.createRef(); + } + /** + * React lifecycle event + */ + componentDidMount() { + if (!this.miradorInstanceRef.current) { + return false; + } + const viewer = OpenSeaDragon({ + id: this.miradorInstanceRef.current.id, + showNavigationControl: false, + }); + const that = this; + fetch(`${this.props.manifest.manifestation.getSequences()[0].getCanvases()[0].getImages()[0].getResource().getServices()[0].id}/info.json`) + .then(response => response.json()) + .then((json) => { + viewer.addTiledImage({ + tileSource: json, + success: (event) => { + const tiledImage = event.item; + + /** + * A callback for the tile after its drawn + * @param {[type]} e event object + */ + const tileDrawnHandler = (e) => { + if (e.tiledImage === tiledImage) { + viewer.removeHandler('tile-drawn', tileDrawnHandler); + that.miradorInstanceRef.current.style.display = 'block'; + } + }; + viewer.addHandler('tile-drawn', tileDrawnHandler); + }, + }); + }) + .catch(error => console.log(error)); + return false; + } + + /** + * Fetches IIIF thumbnail URL + */ + thumbnail() { + const thumb = this.props.manifest.manifestation.getThumbnail() || { id: 'http://placekitten.com/200/300' }; + return thumb.id; + } + + /** + * Return style attributes + */ + styleAttributes() { + return { width: `${this.props.window.xywh[2]}px`, height: `${this.props.window.xywh[3]}px` }; + } + + /** + * Renders things + * @param {object} props (from react/redux) + */ + render() { + return ( +
+ + +
+
+ ); + } +} + +Window.propTypes = { + window: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types + manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types +}; + +Window.defaultProps = { + manifest: null, +}; + +/** + * mapStateToProps - used to hook up connect to action creators + * @memberof Window + * @private + */ +const mapStateToProps = ({ windows, manifests }, props) => { + const window = windows.find(win => props.id === win.id); + return { + window, + manifest: manifests[window.manifestId], + }; +}; + +export default connect(mapStateToProps)(Window); diff --git a/packages/mirador3-app-base/package.json b/packages/mirador3-app-base/package.json index 8ed8de7..3575027 100644 --- a/packages/mirador3-app-base/package.json +++ b/packages/mirador3-app-base/package.json @@ -66,7 +66,7 @@ "workbox-webpack-plugin": "3.6.3" }, "scripts": { - "dist": "node_modules/.bin/webpack --config ./config/webpack.config.dist.js", + "dist": "webpack --config ./config/webpack.config.dist.js", "lint": "node_modules/.bin/eslint ./", "start": "node scripts/start.js", "build": "node scripts/build.js", diff --git a/packages/mirador3-app-base/src/styles/index.scss b/packages/mirador3-app-base/src/styles/index.scss index afa8b27..62ab946 100644 --- a/packages/mirador3-app-base/src/styles/index.scss +++ b/packages/mirador3-app-base/src/styles/index.scss @@ -34,11 +34,15 @@ body { position: relative; } - &-window-heading { + &-window-top-bar { background: linear-gradient(to bottom, rgba(0, 0, 0, .65) 0%, rgba(0, 0, 0, 0) 100%); color: white; position: absolute; - z-index: 10; + z-index: 10; + + h3 { + margin: 0; + } } &-osd-container { diff --git a/packages/mirador3-common/package.json b/packages/mirador3-common/package.json index e4c0b7b..fd190fd 100644 --- a/packages/mirador3-common/package.json +++ b/packages/mirador3-common/package.json @@ -10,8 +10,8 @@ "test": "npm run lint && jest -c jest.json", "test:watch": "jest -c jest.json --watch", "test:coverage": "jest -c jest.json --coverage", - "build": "webpack --mode production", - "build:watch": "node_modules/.bin/webpack --watch" + "build": "webpack", + "build:watch": "webpack --watch" }, "dependencies": { "css-ns": "^1.2.2", diff --git a/packages/mirador3-common/src/components/WindowTopBar.jsx b/packages/mirador3-common/src/components/WindowTopBar.jsx new file mode 100644 index 0000000..32d66da --- /dev/null +++ b/packages/mirador3-common/src/components/WindowTopBar.jsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { actions } from 'mirador3-core'; +import { ns } from '../config/css-ns'; + + +/** + * WindowTopBar + */ +class WindowTopBarComponent extends React.Component { + /** + * render - description + * @return {type} description + */ + render() { + return ( +
+

{this.props.manifest.manifestation.getLabel().map(label => label.value)[0]}

+ +
+ ); + } +} +// +// /** +// * mapStateToProps - used to hook up connect to action creators +// * @memberof Window +// * @private +// */ +// const mapStateToProps = ({ windows, manifests }, props) => { +// const window = windows.find(win => props.windowId === win.id); +// return { +// window, +// // +// manifest: manifests[window.manifestId], +// }; +// }; + +/** + * mapDispatchToProps - used to hook up connect to action creators + * @memberof ManifestListItem + * @private + */ +const mapDispatchToProps = dispatch => ({ + removeWindow: windowId => ( + dispatch(actions.removeWindow(windowId)) + ), +}); + +WindowTopBarComponent.propTypes = { + manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types + removeWindow: PropTypes.func.isRequired, + windowId: PropTypes.string.isRequired, +}; + +WindowTopBarComponent.defaultProps = { + manifest: null, +}; + + +export const WindowTopBar = connect(null, mapDispatchToProps)(WindowTopBarComponent); diff --git a/packages/mirador3-common/src/components/index.js b/packages/mirador3-common/src/components/index.js index c98db24..cc24660 100644 --- a/packages/mirador3-common/src/components/index.js +++ b/packages/mirador3-common/src/components/index.js @@ -3,4 +3,5 @@ export * from './Display'; export * from './ManifestListItem'; export * from './ManifestMetadata'; export * from './Window'; +export * from './WindowTopBar'; export * from './Workspace'; diff --git a/packages/mirador3-common/src/components/test/Window.test.js b/packages/mirador3-common/src/components/test/Window.test.js index 6daa0a9..8e98b30 100644 --- a/packages/mirador3-common/src/components/test/Window.test.js +++ b/packages/mirador3-common/src/components/test/Window.test.js @@ -18,7 +18,8 @@ describe('Window', () => { }); it('returns the width and height style attribute', () => { - expect(shallow().dive().instance().styleAttributes()) + wrapper = shallow(, { context: { store } }); + expect(wrapper.dive().instance().styleAttributes()) .toEqual({ width: '400px', height: '400px' }); }); @@ -26,7 +27,6 @@ describe('Window', () => { expect(wrapper.find('.mirador-window').prop('style')).toHaveProperty('width', '400px'); expect(wrapper.find('.mirador-window').prop('style')).toHaveProperty('height', '400px'); expect(wrapper.find('div.mirador-window').length).toBe(1); - expect(wrapper.find('div.mirador-window h3').text()).toBe('Test 24 Manifest: Image with IIIF Service - adapted with real image'); expect(wrapper.find('div.mirador-window img').prop('src')).toBe('http://placekitten.com/200/300'); }); diff --git a/packages/mirador3-common/src/components/test/WindowTopBar.test.js b/packages/mirador3-common/src/components/test/WindowTopBar.test.js new file mode 100644 index 0000000..207120c --- /dev/null +++ b/packages/mirador3-common/src/components/test/WindowTopBar.test.js @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { actions, store } from 'mirador3-core'; +import { WindowTopBar } from '../WindowTopBar'; +import fixture from './fixtures/24.json'; + +describe('Window', () => { + let wrapper; + let window; + beforeEach(() => { + store.dispatch(actions.receiveManifest('foo', fixture)); + store.dispatch(actions.addWindow({ manifestId: 'foo' })); + const manifest = store.getState().manifests.foo; + [window] = store.getState().windows; + wrapper = shallow() + .dive(); + }); + + it('renders without an error', () => { + expect(wrapper.find('div.mirador-window-top-bar h3').text()).toBe('Test 24 Manifest: Image with IIIF Service - adapted with real image'); + expect(wrapper.find('button.mirador-window-close')); + }); +}); diff --git a/packages/mirador3-core/package.json b/packages/mirador3-core/package.json index 450d013..aade1cd 100644 --- a/packages/mirador3-core/package.json +++ b/packages/mirador3-core/package.json @@ -10,8 +10,8 @@ "test": "npm run lint && jest -c jest.json", "test:watch": "jest -c jest.json --watch", "test:coverage": "jest -c jest.json --coverage", - "build": "node_modules/.bin/webpack", - "build:watch": "node_modules/.bin/webpack --watch" + "build": "webpack", + "build:watch": "webpack --watch" }, "dependencies": { "jest-fetch-mock": "^2.0.1",