Skip to content
Snippets Groups Projects
Unverified Commit 5f1aefa4 authored by Jack Reed's avatar Jack Reed Committed by GitHub
Browse files

Merge pull request #3018 from ProjectMirador/dynamic-companion-windows-2

Add a CompanionWindowRegistry for plugins to register custom companion types
parents 9e576d47 d07d14d1
No related branches found
No related tags found
No related merge requests found
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Mirador</title>
</head>
<body>
<div id="mirador" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;"></div>
<script src="../../../../node_modules/react/umd/react.development.js"></script>
<script src="../../../../node_modules/react-dom/umd/react-dom.development.js"></script>
<script>document.write("<script type='text/javascript' src='../../../../dist/mirador.min.js?v=" + Date.now() + "'><\/script>");</script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
const config = { id: 'mirador', windows: [{manifestId: 'https://purl.stanford.edu/hg676jb4964/iiif/manifest'}] };
const AddPluginComponentA = (props) => (
<div id="add-plugin-companion-window">
Plugin A
</div>
);
const AddPluginComponentB = ({TabButton, PluginComponents, dispatch, ...otherProps}) => (
<TabButton id="add-plugin-companion-window-button" {...otherProps} label="P" value="pluginComponentA" />
);
const addPluginA = {
target: 'CompanionWindowFactory',
companionWindowKey: 'pluginComponentA',
mode: 'add',
component: AddPluginComponentA,
};
const addPluginB = {
target: 'WindowSideBarButtons',
mode: 'add',
component: AddPluginComponentB,
};
const miradorInstance = Mirador.viewer(config, [addPluginA, addPluginB]);
</script>
</body>
</html>
describe('add plugins for companion windows', () => {
beforeAll(async () => {
await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/plugins/companionWindow.html');
await expect(page).toMatchElement('.mirador-viewer');
await page.waitFor(1000);
});
it('added a plugin to the window sidebar and companion window', async () => {
await expect(page).toClick('button[aria-label="Toggle sidebar"]');
await page.waitFor(1000);
await expect(page).toMatchElement('.mirador-companion-window-left.mirador-window-sidebar-info-panel');
await expect(page).toMatchElement('#add-plugin-companion-window-button');
await expect(page).toClick('#add-plugin-companion-window-button');
await expect(page).toMatchElement('#add-plugin-companion-window');
});
});
......@@ -3,6 +3,7 @@ import {
connectPluginsToStore,
addPluginReducersToStore,
createTargetToPluginMapping,
addPluginsToCompanionWindowsRegistry,
} from '../../../src/extend/pluginPreprocessing';
......@@ -108,6 +109,26 @@ describe('connectPluginsToStore', () => {
});
});
describe('addPluginsToCompanionWindowsRegistry', () => {
it('adds plugin references to the companion window registry', () => {
/** */
const ComponentA = props => null;
const plugins = [
{
companionWindowKey: 'xyz',
component: ComponentA,
mode: 'add',
target: 'CompanionWindowFactory',
},
];
const result = addPluginsToCompanionWindowsRegistry(plugins);
expect(result.xyz).toBe(ComponentA);
});
});
describe('addPluginReducersToStore', () => {
const store = { replaceReducer: jest.fn() };
const createRootReducer = jest.fn(pluginReducers => pluginReducers);
......
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ThumbnailNavigation from '../containers/ThumbnailNavigation';
import WindowSideBarAnnotationsPanel from '../containers/WindowSideBarAnnotationsPanel';
import WindowSideBarInfoPanel from '../containers/WindowSideBarInfoPanel';
import WindowSideBarCanvasPanel from '../containers/WindowSideBarCanvasPanel';
import AttributionPanel from '../containers/AttributionPanel';
import SearchPanel from '../containers/SearchPanel';
import LayersPanel from '../containers/LayersPanel';
import CustomPanel from '../containers/CustomPanel';
import CompanionWindowRegistry from '../lib/CompanionWindowRegistry';
/**
* Render a companion window using the appropriate component for the content
......@@ -16,27 +9,11 @@ export class CompanionWindowFactory extends Component {
/** */
render() {
const { content, windowId, id } = this.props;
const type = CompanionWindowRegistry[content];
switch (content) {
case 'info':
return (<WindowSideBarInfoPanel id={id} windowId={windowId} />);
case 'canvas':
return (<WindowSideBarCanvasPanel id={id} windowId={windowId} />);
case 'annotations':
return <WindowSideBarAnnotationsPanel id={id} windowId={windowId} />;
case 'thumbnailNavigation':
return <ThumbnailNavigation id={id} windowId={windowId} />;
case 'attribution':
return <AttributionPanel id={id} windowId={windowId} />;
case 'search':
return <SearchPanel id={id} windowId={windowId} />;
case 'layers':
return <LayersPanel id={id} windowId={windowId} />;
case 'custom':
return <CustomPanel id={id} windowId={windowId} />;
default:
return (<></>);
}
if (!type) return <></>;
return React.createElement(type, { id, windowId });
}
}
......
......@@ -10,6 +10,7 @@ import AnnotationIcon from '@material-ui/icons/CommentSharp';
import AttributionIcon from '@material-ui/icons/CopyrightSharp';
import LayersIcon from '@material-ui/icons/LayersSharp';
import SearchIcon from '@material-ui/icons/SearchSharp';
import { PluginHook } from './PluginHook';
import CanvasIndexIcon from './icons/CanvasIndexIcon';
import { keys, chars } from '../lib/KeyHelper';
/**
......@@ -63,6 +64,7 @@ export class WindowSideBarButtons extends Component {
*/
handleChange(event, value) {
const { addCompanionWindow } = this.props;
const tab = event.target;
this.selectTab(tab);
addCompanionWindow(value);
......@@ -138,6 +140,7 @@ export class WindowSideBarButtons extends Component {
hasSearchResults,
hasSearchService,
panels,
PluginComponents,
sideBarPanel,
t,
} = this.props;
......@@ -217,6 +220,7 @@ export class WindowSideBarButtons extends Component {
)}
/>
)}
<PluginHook TabButton={TabButton} PluginComponents={PluginComponents} />
</Tabs>
);
}
......@@ -231,6 +235,7 @@ WindowSideBarButtons.propTypes = {
hasSearchResults: PropTypes.bool,
hasSearchService: PropTypes.bool,
panels: PropTypes.arrayOf(PropTypes.bool),
PluginComponents: PropTypes.array, // eslint-disable-line react/forbid-prop-types
sideBarPanel: PropTypes.string,
t: PropTypes.func,
};
......@@ -243,6 +248,7 @@ WindowSideBarButtons.defaultProps = {
hasSearchResults: false,
hasSearchService: false,
panels: [],
PluginComponents: null,
sideBarPanel: 'closed',
t: key => key,
};
......@@ -7,6 +7,7 @@ import {
addPluginReducersToStore,
connectPluginsToStore,
createTargetToPluginMapping,
addPluginsToCompanionWindowsRegistry,
} from './pluginPreprocessing';
/** */
......@@ -19,6 +20,7 @@ export default function PluginProvider(props) {
const validPlugins = filterValidPlugins(plugins);
const connectedPlugins = connectPluginsToStore(validPlugins);
createRootReducer && addPluginReducersToStore(store, createRootReducer, validPlugins);
addPluginsToCompanionWindowsRegistry(connectedPlugins);
setPluginMap(createTargetToPluginMapping(connectedPlugins));
}, []);
......
import update from 'lodash/update';
import { connect } from 'react-redux';
import { validatePlugin } from './pluginValidation';
import CompanionWindowRegistry from '../lib/CompanionWindowRegistry';
/**
* Returns a mapping from targets to plugins and modes
......@@ -42,6 +43,15 @@ export function addPluginReducersToStore(store, createRootReducer, plugins) {
store.replaceReducer(createRootReducer(pluginReducers));
}
/** */
export function addPluginsToCompanionWindowsRegistry(plugins) {
plugins.filter(p => p.companionWindowKey).forEach((plugin) => {
CompanionWindowRegistry[plugin.companionWindowKey] = plugin.component;
});
return CompanionWindowRegistry;
}
/** */
function splitPluginsByValidation(plugins) {
const splittedPlugins = { invalidPlugins: [], validPlugins: [] };
......
import ThumbnailNavigation from '../containers/ThumbnailNavigation';
import WindowSideBarAnnotationsPanel from '../containers/WindowSideBarAnnotationsPanel';
import WindowSideBarInfoPanel from '../containers/WindowSideBarInfoPanel';
import WindowSideBarCanvasPanel from '../containers/WindowSideBarCanvasPanel';
import AttributionPanel from '../containers/AttributionPanel';
import SearchPanel from '../containers/SearchPanel';
import LayersPanel from '../containers/LayersPanel';
import CustomPanel from '../containers/CustomPanel';
const map = {
annotations: WindowSideBarAnnotationsPanel,
attribution: AttributionPanel,
canvas: WindowSideBarCanvasPanel,
custom: CustomPanel,
info: WindowSideBarInfoPanel,
layers: LayersPanel,
search: SearchPanel,
thumbnailNavigation: ThumbnailNavigation,
};
export default map;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment