Skip to content

Commit

Permalink
Merge pull request #67 from gerdesque/m4_update
Browse files Browse the repository at this point in the history
M4 update
  • Loading branch information
lutzhelm authored Nov 8, 2024
2 parents 03e648c + c89a971 commit 85774ae
Show file tree
Hide file tree
Showing 23 changed files with 732 additions and 456 deletions.
17 changes: 10 additions & 7 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
{
"env": {
"jest/globals": true
},
"extends": ["airbnb"],
"env": {},
"extends": ["airbnb", "plugin:jest/recommended"],
"globals": {
"page": true,
"document": true
},
"parser": "babel-eslint",
"plugins": ["jest"],
"parser": "@babel/eslint-parser",
"plugins": ["babel", "jest", "react", "react-hooks"],
"rules": {
"import/prefer-default-export": "off",
"import/no-extraneous-dependencies": "off",
"no-console": "warn",
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"react/jsx-fragments": "off",
"react/jsx-props-no-spreading": "off",
"react/prefer-stateless-function": "off",
"react/function-component-definition": "off"
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@
/umd
npm-debug.log*
package-lock.json
.cache
dist
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![npm package][npm-badge]][npm]
[![Coveralls][coveralls-badge]][coveralls]

`mirador-dl-plugin` is a Mirador 3 plugin that adds manifest-provided download links (e.g. `rendering`) to the window options menu. A [live demo](https://mirador-download-plugin.netlify.app/) with several institutions' manifests is available for testing.
`mirador-dl-plugin` is a Mirador 4 plugin that adds manifest-provided download links (e.g. `rendering`) to the window options menu. A [live demo](https://mirador-download-plugin.netlify.app/) with several institutions' manifests is available for testing.

![download option in menu](https://user-images.githubusercontent.com/5402927/87057974-5e665a80-c1bc-11ea-8f10-7b783bdc972f.png)

Expand All @@ -22,7 +22,7 @@

## Installation

`mirador-dl-plugin` requires an instance of Mirador 3. See the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) for examples of embedding Mirador within an application and additional information about plugins. See the [live demo's index.js](https://github.com/ProjectMirador/mirador-dl-plugin/blob/master/demo/src/index.js) for an example of importing and configuring `mirador-dl-plugin`.
`mirador-dl-plugin` requires an instance of Mirador 4. See the [Mirador wiki](https://github.com/ProjectMirador/mirador/wiki) for examples of embedding Mirador within an application and additional information about plugins. See the [live demo's index.js](https://github.com/ProjectMirador/mirador-dl-plugin/blob/master/demo/src/index.js) for an example of importing and configuring `mirador-dl-plugin`.

## Configuration

Expand Down
232 changes: 109 additions & 123 deletions __tests__/CanvasDownloadLinks.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { shallow } from 'enzyme';
import Link from '@material-ui/core/Link';
import Typography from '@material-ui/core/Typography';
import { OSDReferences } from 'mirador/dist/es/src/plugins/OSDReferences';
import CanvasDownloadLinks from '../src/CanvasDownloadLinks';
import RenderingDownloadLink from '../src/RenderingDownloadLink';
import { render, screen } from './test-utils';

/**
* Helper function to render the CanvasDownloadLinks component with custom props.
*/
function createWrapper(props) {
return shallow(
return render(
<CanvasDownloadLinks
canvasId="abc123"
canvasLabel="My Canvas Label"
Expand All @@ -22,10 +22,9 @@ function createWrapper(props) {
}

describe('CanvasDownloadLinks', () => {
let wrapper;
const canvas = {
id: 'abc123',
getCanonicalImageUri: width => (
getCanonicalImageUri: (width) => (
width
? `http://example.com/iiif/abc123/full/${width},/0/default.jpg`
: 'http://example.com/iiif/abc123/full/4000,/0/default.jpg'
Expand All @@ -40,181 +39,168 @@ describe('CanvasDownloadLinks', () => {
},
],
};
const viewport = {
getBounds: () => ({
x: 0, y: 0, width: 4000, height: 1000,
}),
};
const zoomedInViewport = {
getBounds: () => ({
x: 0, y: 0, width: 2000, height: 500,
}),
};

const zoomedOutViewport = {
getBounds: () => ({
x: 0, y: 0, width: 6000, height: 1000,
}),
};
let currentBoundsSpy;

const zoomedIntoNonImageSpaceViewport = {
getBounds: () => ({
x: -100, y: 100, width: 2000, height: 500,
}),
};
beforeEach(() => {
currentBoundsSpy = jest.spyOn(CanvasDownloadLinks.prototype, 'currentBounds');
});

beforeAll(() => {
OSDReferences.set('wid123', {
current: { viewport },
});
OSDReferences.set('zoomedInWindow', {
current: { viewport: zoomedInViewport },
});
OSDReferences.set('zoomedOutWindow', {
current: { viewport: zoomedOutViewport },
});
OSDReferences.set('zoomedIntoNonImageSpaceWindow', {
current: { viewport: zoomedIntoNonImageSpaceViewport },
});
afterEach(() => {
currentBoundsSpy.mockRestore();
});

it('renders canvas label in an h3 typography', () => {
wrapper = createWrapper({ canvas });
expect(
wrapper.find(Typography)
.find({ variant: 'h3' })
.props().children,
).toEqual('My Canvas Label');
it('renders the canvas label as an h3 heading', () => {
createWrapper({ canvas });

const headingElement = screen.getByText('My Canvas Label');
expect(headingElement).toBeInTheDocument();
expect(headingElement.tagName).toBe('H3');
});

it('renders canvas level renderings', () => {
wrapper = createWrapper({ canvas });
expect(
wrapper.find(RenderingDownloadLink).length,
).toEqual(1);
describe('Canvas Renderings', () => {
it('includes a canvas-level rendering as a download link', () => {
createWrapper({ canvas });

const downloadLink = screen.getByRole('link', { name: /Whole image \(4000 x 1000px\)/i });
expect(downloadLink).toBeInTheDocument();
});
});

describe('Zoomed region link', () => {
describe('Zoomed Region Links', () => {
const infoResponse = {
json: { width: 4000, height: 1000 },
};

it('it does not render a link when the viewer is zoomed out/at the entire image', () => {
wrapper = createWrapper({ canvas, infoResponse, windowId: 'zoomedOutWindow' });
expect(wrapper.find(Link).length).toBe(2);
it('does not render a zoom link when viewer is zoomed out to full image', () => {
currentBoundsSpy.mockImplementation(() => ({
x: 0, y: 0, width: 6000, height: 1000,
}));

createWrapper({ canvas, infoResponse, windowId: 'zoomedOutWindow' });

wrapper = createWrapper({ canvas, infoResponse, windowId: 'wid123' });
expect(wrapper.find(Link).length).toBe(2);
const zoomedLink = screen.queryByText('Zoomed region (6000 x 1000px)');
expect(zoomedLink).not.toBeInTheDocument();
});

it('does not render a link when the viewer is zoomed into non-image space (e.g. a reponse the image server cannot handle)', () => {
wrapper = createWrapper({ canvas, infoResponse, windowId: 'zoomedIntoNonImageSpaceWindow' });
it('does not render a zoom link when zoomed into an area outside of the image bounds', () => {
currentBoundsSpy.mockImplementation(() => ({
x: -100, y: 100, width: 2000, height: 500,
}));

expect(wrapper.find(Link).length).toBe(2);
createWrapper({ canvas, infoResponse, windowId: 'zoomedIntoNonImageSpaceWindow' });

const zoomedLink = screen.queryByText('Zoomed region (2000 x 500px)');
expect(zoomedLink).not.toBeInTheDocument();
});

it('is present when the viewer is zoomed into the image', () => {
wrapper = createWrapper({ canvas, infoResponse, windowId: 'zoomedInWindow' });
it('renders a zoomed region link when zoomed into a valid area of the image', () => {
currentBoundsSpy.mockImplementation(() => ({
x: 0, y: 0, width: 2000, height: 500,
}));

createWrapper({ canvas, infoResponse, windowId: 'zoomedInWindow' });

expect(wrapper.find(Link).length).toBe(3);
expect(
wrapper
.find(Link)
.find({ href: 'http://example.com/iiif/abc123/0,0,2000,500/full/0/default.jpg?download=true' })
.props().children,
).toEqual('Zoomed region (2000 x 500px)');
const zoomedLink = screen.queryByText('Zoomed region (2000 x 500px)');
expect(zoomedLink).toBeInTheDocument();
});

it('is not present when the window is in book or gallery view (only single view)', () => {
wrapper = createWrapper({
it('does not render a zoomed region link in non-single view types (e.g., book, gallery views)', () => {
currentBoundsSpy.mockImplementation(() => ({
x: 0, y: 0, width: 2000, height: 500,
}));

createWrapper({
canvas, infoResponse, viewType: 'book', windowId: 'zoomedInWindow',
});
const zoomedLink = screen.queryByText('Zoomed region (2000 x 500px)');
expect(zoomedLink).not.toBeInTheDocument();

expect(wrapper.find(Link).length).toBe(2);

wrapper = createWrapper({
createWrapper({
canvas, infoResponse, viewType: 'gallery', windowId: 'zoomedInWindow',
});

expect(wrapper.find(Link).length).toBe(2);
const zoomedLinkGallery = screen.queryByText('Zoomed region (2000 x 500px)');
expect(zoomedLinkGallery).not.toBeInTheDocument();
});

describe('when the zoom link is set to be restricted', () => {
it('has just the whole image link from the sizes and does not present a zoomed region link', () => {
wrapper = createWrapper({
describe('Download Link Size Restrictions', () => {
it('renders only a single download link based on the restricted sizes', () => {
createWrapper({
canvas,
infoResponse: {
json: {
width: 4000,
height: 1000,
sizes: [{
width: 400,
height: 100,
}],
sizes: [{ width: 400, height: 100 }],
},
},
restrictDownloadOnSizeDefinition: true,
windowId: 'zoomedInWindow',
});

expect(wrapper.find(Link).length).toBe(1);
expect(wrapper.find(Link).props().children).toEqual('Whole image (400 x 100px)');
const downloadLink = screen.getByRole('link', { name: /Whole image \(400 x 100px\)/i });
expect(screen.getAllByRole('link')).toHaveLength(2); // Should only show small-size version and link to PDF.
expect(downloadLink).toBeInTheDocument();
});
});
});

describe('when there is are sizes defined in the infoResponse', () => {
describe('When Defined Sizes Are Present in infoResponse', () => {
const sizes = [
{ width: 4000, height: 1000 },
{ width: 2000, height: 500 },
{ width: 1000, height: 250 },
];
it('uses those sizes for links in the download dialog', () => {
wrapper = createWrapper({ canvas, infoResponse: { json: { sizes } } });

// console.log(wrapper.debug());
expect(wrapper.find(Link).at(0).props().children).toEqual('Whole image (4000 x 1000px)');
expect(wrapper.find(Link).at(1).props().children).toEqual('Whole image (2000 x 500px)');
expect(wrapper.find(Link).at(2).props().children).toEqual('Whole image (1000 x 250px)');
const viewport = {
getBounds: () => ({
x: 0, y: 0, width: 4000, height: 1000,
}),
};
OSDReferences.set('wid123', {
current: { viewport },
});
it('renders download links for all specified sizes in the dialog', () => {
createWrapper({ canvas, infoResponse: { json: { sizes } } });

const link1 = screen.getByRole('link', { name: /Whole image \(4000 x 1000px\)/i });
const link2 = screen.getByRole('link', { name: /Whole image \(2000 x 500px\)/i });
const link3 = screen.getByRole('link', { name: /Whole image \(1000 x 250px\)/i });

expect(link1).toBeInTheDocument();
expect(link2).toBeInTheDocument();
expect(link3).toBeInTheDocument();
});
});

describe('when there are no defined sizes', () => {
it('renders a link to the whole image', () => {
wrapper = createWrapper({ canvas });
expect(
wrapper
.find(Link)
.find({ href: 'http://example.com/iiif/abc123/full/full/0/default.jpg?download=true' })
.props()
.children,
).toEqual('Whole image (4000 x 1000px)');
describe('When No Sizes Are Defined in infoResponse', () => {
it('renders a single link to the full-size image', () => {
createWrapper({ canvas });

const link = screen.getByRole('link', { name: /Whole image \(4000 x 1000px\)/i });
expect(link).toBeInTheDocument();
expect(link).toHaveAttribute('href', 'http://example.com/iiif/abc123/full/full/0/default.jpg?download=true');
});

describe('when the image is > 1000px wide', () => {
it('renders a link to a small image (1000px wide), and calculates the correct height', () => {
wrapper = createWrapper({ canvas });
expect(wrapper.find(Link).length).toEqual(2);
expect(
wrapper
.find(Link)
.find({ href: 'http://example.com/iiif/abc123/full/1000,/0/default.jpg?download=true' })
.length,
).toEqual(1);
expect(
wrapper
.find(Link)
.find({ href: 'http://example.com/iiif/abc123/full/1000,/0/default.jpg?download=true' })
.props().children,
).toEqual('Whole image (1000 x 250px)');
describe('For Images Wider Than 1000px', () => {
it('renders links for both full-size and 1000px wide versions', () => {
createWrapper({ canvas });

const link1 = screen.getByRole('link', { name: /Whole image \(4000 x 1000px\)/i });
expect(link1).toHaveAttribute('href', 'http://example.com/iiif/abc123/full/full/0/default.jpg?download=true');

const link2 = screen.getByRole('link', { name: /Whole image \(1000 x 250px\)/i });
expect(link2).toHaveAttribute('href', 'http://example.com/iiif/abc123/full/1000,/0/default.jpg?download=true');
});
});

describe('when the image is < 1000px wide', () => {
it('does not render a link to a small image', () => {
describe('For Images Less Than 1000px Wide', () => {
it('does not render a smaller version link if image is under 1000px wide', () => {
canvas.getWidth = () => 999;
wrapper = createWrapper({ canvas });
expect(wrapper.find(Link).length).toEqual(1); // Does not include the 2nd link
createWrapper({ canvas });

const links = screen.getAllByRole('link');
expect(links).toHaveLength(2); // Should only show full-size version and link to PDF.
});
});
});
Expand Down
Loading

0 comments on commit 85774ae

Please sign in to comment.