Skip to content
Snippets Groups Projects
Commit a529bea6 authored by Chris Beer's avatar Chris Beer
Browse files

Handle fetching annotations in a saga

parent 1a9e9036
No related branches found
No related tags found
No related merge requests found
......@@ -31,23 +31,6 @@ describe('annotation actions', () => {
expect(actions.receiveAnnotation(targetId, annotationId, json)).toEqual(expectedAction);
});
});
describe('fetchAnnotation', () => {
describe('success response', () => {
beforeEach(() => {
fetch.mockResponseOnce(JSON.stringify({ data: '12345' })); // eslint-disable-line no-undef
});
it('dispatches the REQUEST_ANNOTATION action', () => {
expect(actions.fetchAnnotation(
'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
)).toEqual({
annotationId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/list/47174896',
targetId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174896',
type: 'mirador/REQUEST_ANNOTATION',
});
});
});
});
it('handles the selectAnnotation action', () => {
const windowId = 'wId1';
......
......@@ -6,7 +6,6 @@ import OSDViewer from '../../../src/containers/OpenSeadragonViewer';
import WindowCanvasNavigationControls from '../../../src/containers/WindowCanvasNavigationControls';
import fixture from '../../fixtures/version-2/019.json';
import emptyCanvasFixture from '../../fixtures/version-2/emptyCanvas.json';
import otherContentFixture from '../../fixtures/version-2/299843.json';
let currentCanvases = Utils.parseManifest(fixture).getSequences()[0].getCanvases();
......@@ -18,7 +17,6 @@ function createWrapper(props) {
canvasLabel="label"
infoResponses={{}}
fetchInfoResponse={() => {}}
fetchAnnotation={() => {}}
currentCanvases={[currentCanvases[1]]}
view="single"
windowId="xyz"
......@@ -123,16 +121,6 @@ describe('WindowViewer', () => {
);
expect(mockFnCanvas2).toHaveBeenCalledTimes(0);
});
it('calls fetchAnnotation when otherContent is present', () => {
const mockFnAnno = jest.fn();
const canvases = Utils.parseManifest(otherContentFixture).getSequences()[0].getCanvases();
currentCanvases = [canvases[0]];
wrapper = createWrapper(
{ currentCanvases, fetchAnnotation: mockFnAnno },
);
expect(mockFnAnno).toHaveBeenCalledTimes(1);
});
});
describe('componentDidUpdate', () => {
......
......@@ -49,27 +49,7 @@ describe('MiradorCanvas', () => {
});
});
});
describe('processAnnotations', () => {
describe('v2', () => {
it('fetches annotations for each annotationList', () => {
const otherContentInstance = new MiradorCanvas(
Utils.parseManifest(otherContentFixture).getSequences()[0].getCanvases()[0],
);
const fetchMock = jest.fn();
otherContentInstance.processAnnotations(fetchMock);
expect(fetchMock).toHaveBeenCalledTimes(1);
});
});
describe('v3', () => {
it('fetches annotations for external items and receives annotations for items that are embedded', () => {
const receiveMock = jest.fn();
const fetchMock = jest.fn();
v3Instance.processAnnotations(fetchMock, receiveMock);
expect(receiveMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledTimes(2);
});
});
});
describe('aspectRatio', () => {
it('calculates a width / height aspectRatio', () => {
expect(instance.aspectRatio).toBeCloseTo(0.667);
......
import { select } from 'redux-saga/effects';
import { expectSaga } from 'redux-saga-test-plan';
import { fetchAnnotations } from '../../../src/state/sagas/annotations';
import { getAnnotations, getCanvases } from '../../../src/state/selectors';
describe('annotation sagas', () => {
describe('fetchAnnotations', () => {
it('requests IIIF v2-style annotations for each visible canvas', () => {
const action = {
visibleCanvases: ['a', 'b'],
windowId: 'foo',
};
return expectSaga(fetchAnnotations, action)
.provide([
[select(getCanvases, { windowId: 'foo' }), [
{ __jsonld: { otherContent: 'annoId' }, id: 'a' },
{ __jsonld: { otherContent: ['alreadyFetched'] }, id: 'b' },
]],
[select(getAnnotations), { a: {}, b: { alreadyFetched: {} } }],
])
.put({
annotationId: 'annoId',
targetId: 'a',
type: 'mirador/REQUEST_ANNOTATION',
})
.run();
});
it('requests IIIF v3-style annotations for each visible canvas', () => {
const action = {
visibleCanvases: ['a', 'b'],
windowId: 'foo',
};
return expectSaga(fetchAnnotations, action)
.provide([
[select(getCanvases, { windowId: 'foo' }), [
{ __jsonld: { annotations: { id: 'annoId', type: 'AnnotationPage' } }, id: 'a' },
]],
[select(getAnnotations), { a: {} }],
])
.put({
annotationId: 'annoId',
targetId: 'a',
type: 'mirador/REQUEST_ANNOTATION',
})
.run();
});
it('handles embedded IIIF v3-style annotations on each visible canvas', () => {
const action = {
visibleCanvases: ['a', 'b'],
windowId: 'foo',
};
const annotations = { id: 'annoId', items: [], type: 'AnnotationPage' };
return expectSaga(fetchAnnotations, action)
.provide([
[select(getCanvases, { windowId: 'foo' }), [
{ __jsonld: { annotations }, id: 'a' },
]],
[select(getAnnotations), { a: {} }],
])
.put({
annotationId: 'annoId',
annotationJson: annotations,
targetId: 'a',
type: 'mirador/RECEIVE_ANNOTATION',
})
.run();
});
});
});
......@@ -29,7 +29,7 @@ export class WindowViewer extends Component {
*/
componentDidMount() {
const {
currentCanvases, fetchInfoResponse, fetchAnnotation, receiveAnnotation,
currentCanvases, fetchInfoResponse,
} = this.props;
if (!this.infoResponseIsInStore()) {
......@@ -38,7 +38,6 @@ export class WindowViewer extends Component {
miradorCanvas.iiifImageResources.forEach((imageResource) => {
fetchInfoResponse({ imageResource });
});
miradorCanvas.processAnnotations(fetchAnnotation, receiveAnnotation);
});
}
}
......@@ -49,7 +48,7 @@ export class WindowViewer extends Component {
*/
componentDidUpdate(prevProps) {
const {
currentCanvases, fetchInfoResponse, fetchAnnotation, receiveAnnotation,
currentCanvases, fetchInfoResponse,
} = this.props;
if (difference(currentCanvases, prevProps.currentCanvases).length > 0
......@@ -59,7 +58,6 @@ export class WindowViewer extends Component {
miradorCanvas.iiifImageResources.forEach((imageResource) => {
fetchInfoResponse({ imageResource });
});
miradorCanvas.processAnnotations(fetchAnnotation, receiveAnnotation);
});
}
}
......
......@@ -57,24 +57,6 @@ export default class MiradorCanvas {
.filter(annotations => annotations && annotations.type === 'AnnotationPage');
}
/** */
processAnnotations(fetchAnnotation, receiveAnnotation) {
// IIIF v2
this.annotationListUris.forEach((uri) => {
fetchAnnotation(this.canvas.id, uri);
});
// IIIF v3
this.canvasAnnotationPages.forEach((annotation) => {
// If there are no items, try to retrieve the referenced resource.
// otherwise the resource should be embedded and just add to the store.
if (!annotation.items) {
fetchAnnotation(this.canvas.id, annotation.id);
} else {
receiveAnnotation(this.canvas.id, annotation.id, annotation);
}
});
}
/**
* Will negotiate a v2 or v3 type of resource
*/
......
......@@ -49,16 +49,6 @@ export function receiveAnnotationFailure(targetId, annotationId, error) {
};
}
/**
* fetchAnnotation - action creator
*
* @param {String} annotationId
* @memberof ActionCreators
*/
export function fetchAnnotation(targetId, annotationId) {
return requestAnnotation(targetId, annotationId);
}
/**
* selectAnnotation - action creator
*
......
import {
all, put, select, takeEvery,
} from 'redux-saga/effects';
import { receiveAnnotation, requestAnnotation } from '../actions';
import { getAnnotations, getCanvases } from '../selectors';
import ActionTypes from '../actions/action-types';
import MiradorCanvas from '../../lib/MiradorCanvas';
/** Fetch annotations for the visible canvases */
export function* fetchAnnotations({ visibleCanvases: visibleCanvasIds, windowId }) {
const canvases = yield select(getCanvases, { windowId });
const visibleCanvases = (canvases || []).filter(c => visibleCanvasIds.includes(c.id));
const annotations = yield select(getAnnotations);
yield all(visibleCanvases.map((canvas) => {
const miradorCanvas = new MiradorCanvas(canvas);
return all([
// IIIF v2
...miradorCanvas.annotationListUris
.filter(uri => !(annotations[canvas.id] && annotations[canvas.id][uri]))
.map(uri => put(requestAnnotation(canvas.id, uri))),
// IIIF v3
...miradorCanvas.canvasAnnotationPages
.filter(annotation => !(annotations[canvas.id] && annotations[canvas.id][annotation.id]))
.map((annotation) => {
// If there are no items, try to retrieve the referenced resource.
// otherwise the resource should be embedded and just add to the store.
if (!annotation.items) {
return put(requestAnnotation(canvas.id, annotation.id));
}
return put(receiveAnnotation(canvas.id, annotation.id, annotation));
}),
]);
}));
}
/** */
export default function* appSaga() {
yield all([
takeEvery(ActionTypes.SET_CANVAS, fetchAnnotations),
]);
}
......@@ -5,6 +5,7 @@ import {
import appSaga from './app';
import iiifSaga from './iiif';
import windowSaga from './windows';
import annotations from './annotations';
/** */
function* launchSaga(saga) {
......@@ -22,6 +23,7 @@ function* launchSaga(saga) {
function getRootSaga(pluginSagas) {
return function* rootSaga() {
const sagas = [
annotations,
appSaga,
iiifSaga,
windowSaga,
......
......@@ -4,10 +4,13 @@ import flatten from 'lodash/flatten';
import AnnotationFactory from '../../lib/AnnotationFactory';
import { getCanvas, getVisibleCanvasIds } from './canvases';
/** */
export const getAnnotations = state => state.annotations;
const getAnnotationsOnCanvas = createSelector(
[
getCanvas,
state => state.annotations,
getAnnotations,
],
(canvas, annotations) => {
if (!annotations || !canvas) return [];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment