mirador-annotation-editor-video 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/__tests__/AnnotationCreation.test.js +62 -28
- package/__tests__/AnnotationExportDialog.test.js +18 -16
- package/__tests__/CanvasListItem.test.js +53 -19
- package/__tests__/LocalStorageAdapter.test.js +1 -1
- package/__tests__/miradorAnnotationPlugin.test.js +97 -70
- package/__tests__/style-mock.js +1 -0
- package/__tests__/test-utils.js +57 -0
- package/demo/src/index.js +9 -4
- package/demo/src/quillConfig.js +34 -0
- package/es/AnnotationExportDialog.js +17 -25
- package/es/CanvasListItem.js +8 -4
- package/es/IIIFUtils.js +35 -3
- package/es/SingleCanvasDialog.js +1 -4
- package/es/TextEditor.js +9 -19
- package/es/annotationForm/AnnotationForm.js +14 -41
- package/es/annotationForm/AnnotationFormBody.js +36 -27
- package/es/annotationForm/AnnotationFormHeader.js +3 -3
- package/es/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +3 -1
- package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlay.js +1 -1
- package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +3 -2
- package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +8 -6
- package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +6 -20
- package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +16 -6
- package/es/annotationForm/AnnotationFormTemplateSelector.js +9 -9
- package/es/annotationForm/AnnotationFormUtils.js +3 -0
- package/es/annotationForm/Debug.js +1 -0
- package/es/annotationForm/DebugInformation.js +27 -0
- package/es/annotationForm/MultiTagsInput.js +4 -1
- package/es/annotationForm/MultipleBodyTemplate.js +7 -9
- package/es/annotationForm/TaggingTemplate.js +0 -1
- package/es/annotationForm/TargetFormSection.js +4 -3
- package/es/annotationForm/TargetSpatialInput.js +4 -3
- package/es/annotationForm/TextCommentInput.js +25 -12
- package/es/annotationForm/TextCommentTemplate.js +0 -1
- package/es/annotationForm/UnsupportedMedia.js +43 -0
- package/es/containers/miradorAnnotationPlugin.js +1 -50
- package/es/custom.css +0 -13
- package/es/index.js +5 -12
- package/es/locales/locales.js +3 -2
- package/es/locales/locales_en.js +1 -1
- package/es/playerReferences.js +2 -1
- package/es/plugins/annotationCreationCompanionWindow.js +5 -8
- package/es/plugins/annotationSaga.js +44 -0
- package/es/plugins/canvasAnnotationsPlugin.js +86 -61
- package/es/plugins/canvasAnnotationsPluginUtils.js +202 -0
- package/es/plugins/externalStorageAnnotationPlugin.js +6 -71
- package/es/plugins/miradorAnnotationPlugin.js +44 -6
- package/es/plugins/windowSideBarButtonsPlugin.js +8 -10
- package/jest.config.js +14 -3
- package/package.json +8 -3
- package/setupJest.js +1 -4
- package/src/AnnotationExportDialog.js +12 -24
- package/src/CanvasListItem.js +4 -3
- package/src/IIIFUtils.js +33 -5
- package/src/SingleCanvasDialog.js +0 -3
- package/src/TextEditor.js +8 -32
- package/src/annotationForm/AnnotationForm.js +8 -47
- package/src/annotationForm/AnnotationFormBody.js +62 -83
- package/src/annotationForm/AnnotationFormHeader.js +3 -3
- package/src/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +3 -9
- package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlay.js +1 -1
- package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +2 -1
- package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +10 -6
- package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +14 -20
- package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +14 -12
- package/src/annotationForm/AnnotationFormTemplateSelector.js +5 -7
- package/src/annotationForm/AnnotationFormUtils.js +2 -0
- package/src/annotationForm/Debug.js +0 -0
- package/src/annotationForm/DebugInformation.js +59 -0
- package/src/annotationForm/MultiTagsInput.js +4 -1
- package/src/annotationForm/MultipleBodyTemplate.js +7 -8
- package/src/annotationForm/TaggingTemplate.js +0 -1
- package/src/annotationForm/TargetFormSection.js +2 -3
- package/src/annotationForm/TargetSpatialInput.js +3 -3
- package/src/annotationForm/TextCommentInput.js +28 -14
- package/src/annotationForm/TextCommentTemplate.js +0 -1
- package/src/annotationForm/UnsupportedMedia.js +31 -0
- package/src/containers/miradorAnnotationPlugin.js +0 -36
- package/src/custom.css +0 -13
- package/src/index.js +10 -15
- package/src/locales/locales.js +3 -1
- package/src/locales/locales_en.js +1 -1
- package/src/playerReferences.js +5 -2
- package/src/plugins/annotationCreationCompanionWindow.js +9 -23
- package/src/plugins/annotationSaga.js +50 -0
- package/src/plugins/canvasAnnotationsPlugin.js +122 -98
- package/src/plugins/canvasAnnotationsPluginUtils.js +199 -0
- package/src/plugins/externalStorageAnnotationPlugin.js +6 -79
- package/src/plugins/miradorAnnotationPlugin.js +32 -4
- package/src/plugins/windowSideBarButtonsPlugin.js +6 -8
- package/webpack.config.js +1 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
## [ 1.1.16]
|
|
4
|
+
|
|
5
|
+
### Change From MAE 1.0.88
|
|
6
|
+
- ADD : Implement Multibody template
|
|
7
|
+
- ADD : Tags suggestion in annotation edition
|
|
8
|
+
- FIX : Use selector to get config data
|
|
9
|
+
- FIX : Clean translation function call
|
|
10
|
+
- FIX : Simplify IIIF annotation generation
|
|
11
|
+
- CLEAN : Remove unused code
|
|
@@ -1,48 +1,82 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
fireEvent, render, screen, waitFor,
|
|
5
|
+
} from './test-utils';
|
|
6
|
+
import TextCommentTemplate from '../src/annotationForm/TextCommentTemplate';
|
|
7
|
+
|
|
8
|
+
const container = document.createElement('div');
|
|
9
|
+
container.setAttribute('data-testid', 'drawContainer');
|
|
10
|
+
|
|
11
|
+
const playerReferences = {
|
|
12
|
+
getContainer: jest.fn().mockReturnValue(container),
|
|
13
|
+
getDisplayedMediaHeight: jest.fn().mockReturnValue(100),
|
|
14
|
+
getDisplayedMediaWidth: jest.fn().mockReturnValue(200),
|
|
15
|
+
getImagePosition: jest.fn().mockReturnValue({ x: 0, y: 10 }),
|
|
16
|
+
getMediaTrueWidth: jest.fn().mockReturnValue(250),
|
|
17
|
+
getMediaType: jest.fn(),
|
|
18
|
+
getScale: jest.fn(),
|
|
19
|
+
getZoom: jest.fn(),
|
|
20
|
+
};
|
|
8
21
|
|
|
9
22
|
/** */
|
|
10
23
|
function createWrapper(props) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
24
|
+
const mockT = jest.fn().mockImplementation((key) => key);
|
|
25
|
+
return render(
|
|
26
|
+
<TextCommentTemplate
|
|
27
|
+
annotation={{}}
|
|
28
|
+
closeFormCompanionWindow={jest.fn()}
|
|
29
|
+
playerReferences={playerReferences}
|
|
30
|
+
saveAnnotation={jest.fn()}
|
|
31
|
+
t={mockT}
|
|
16
32
|
windowId="abc"
|
|
17
33
|
{...props}
|
|
18
34
|
/>,
|
|
19
35
|
);
|
|
20
36
|
}
|
|
21
37
|
|
|
22
|
-
describe('
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
expect(wrapper.dive().find('form').length).toBe(1);
|
|
38
|
+
describe('TextCreation', () => {
|
|
39
|
+
it('renders a note', () => {
|
|
40
|
+
createWrapper();
|
|
41
|
+
expect(screen.getAllByText('note'));
|
|
27
42
|
});
|
|
28
|
-
it('
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
it('has button tool selection', () => {
|
|
44
|
+
createWrapper();
|
|
45
|
+
screen.debug();
|
|
46
|
+
|
|
47
|
+
const toolSelection = screen.getByTestId('tool_selection');
|
|
48
|
+
expect(toolSelection).toBeInTheDocument();
|
|
49
|
+
const btns = screen.getAllByLabelText('select_cursor');
|
|
50
|
+
expect(btns).toHaveLength(3);
|
|
31
51
|
});
|
|
32
52
|
it('adds the AnnotationDrawing component', () => {
|
|
33
|
-
|
|
34
|
-
expect(
|
|
53
|
+
document.body.appendChild(container);
|
|
54
|
+
expect(screen.getByTestId('drawContainer')).toBeInTheDocument();
|
|
55
|
+
|
|
56
|
+
expect(container.querySelector('canvas')).not.toBeInTheDocument();
|
|
57
|
+
createWrapper();
|
|
58
|
+
expect(container.querySelector('canvas')).toBeInTheDocument();
|
|
59
|
+
document.body.removeChild(container);
|
|
35
60
|
});
|
|
36
61
|
it('adds the TextEditor component', () => {
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
createWrapper();
|
|
63
|
+
const textEditor = screen.getByTestId('textEditor');
|
|
64
|
+
expect(textEditor).toBeInTheDocument();
|
|
65
|
+
});
|
|
66
|
+
it('adds the annotation form footer', () => {
|
|
67
|
+
createWrapper();
|
|
68
|
+
expect(screen.getByRole('button', { name: 'save' })).toBeInTheDocument();
|
|
69
|
+
expect(screen.getByRole('button', { name: 'cancel' })).toBeInTheDocument();
|
|
39
70
|
});
|
|
40
|
-
it('adds the ImageFormField component', () => {
|
|
41
|
-
|
|
42
|
-
|
|
71
|
+
it('adds the ImageFormField component', async () => {
|
|
72
|
+
createWrapper();
|
|
73
|
+
const toolSelection = screen.getByTestId('tool_selection');
|
|
74
|
+
expect(toolSelection).toBeInTheDocument();
|
|
75
|
+
expect(screen.getByLabelText('add_a_rectangle'));
|
|
76
|
+
expect(screen.getByLabelText('add_a_circle'));
|
|
43
77
|
});
|
|
44
78
|
it('can handle annotations without target selector', () => {
|
|
45
|
-
wrapper = createWrapper({
|
|
79
|
+
const wrapper = createWrapper({
|
|
46
80
|
annotation: {
|
|
47
81
|
body: {
|
|
48
82
|
purpose: 'commenting',
|
|
@@ -51,6 +85,6 @@ describe('AnnotationCreation', () => {
|
|
|
51
85
|
target: {},
|
|
52
86
|
},
|
|
53
87
|
});
|
|
54
|
-
wrapper.
|
|
88
|
+
expect(wrapper).toBeDefined();
|
|
55
89
|
});
|
|
56
90
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import MenuItem from '@material-ui/core/MenuItem';
|
|
2
|
+
|
|
4
3
|
import AnnotationExportDialog from '../src/AnnotationExportDialog';
|
|
4
|
+
import { screen, render, waitFor } from './test-utils';
|
|
5
5
|
|
|
6
6
|
window.URL.createObjectURL = jest.fn((data) => ('downloadurl'));
|
|
7
7
|
|
|
@@ -22,12 +22,15 @@ const adapter = jest.fn(() => (
|
|
|
22
22
|
|
|
23
23
|
/** */
|
|
24
24
|
function createWrapper(props) {
|
|
25
|
-
|
|
25
|
+
const mockT = jest.fn().mockImplementation((key) => key);
|
|
26
|
+
return render(
|
|
26
27
|
<AnnotationExportDialog
|
|
27
28
|
canvases={[]}
|
|
29
|
+
classes={{ listitem: 'testClass' }}
|
|
28
30
|
config={{ annotation: { adapter } }}
|
|
29
31
|
handleClose={jest.fn()}
|
|
30
32
|
open
|
|
33
|
+
t={mockT}
|
|
31
34
|
{...props}
|
|
32
35
|
/>,
|
|
33
36
|
);
|
|
@@ -35,19 +38,18 @@ function createWrapper(props) {
|
|
|
35
38
|
|
|
36
39
|
describe('AnnotationExportDialog', () => {
|
|
37
40
|
it('renders download link for every annotation page', async () => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
createWrapper(
|
|
42
|
+
{
|
|
43
|
+
canvases: [
|
|
44
|
+
{ id: 'canvas/1' },
|
|
45
|
+
{ id: 'canvas/2' },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
expect(screen.getByText(/no_annotation/i)).toBeInTheDocument();
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(wrapper.text()).toEqual(expect.not.stringContaining('No annotations stored yet.'));
|
|
50
|
-
expect(wrapper.find(MenuItem).some({ 'aria-label': 'Export annotations for canvas/1' })).toBe(true);
|
|
51
|
-
expect(wrapper.find(MenuItem).some({ 'aria-label': 'Export annotations for canvas/2' })).toBe(true);
|
|
51
|
+
await waitFor(() => screen.getAllByText(/export_annotation_for/i));
|
|
52
|
+
const elements = screen.getAllByText(/export_annotation_for/);
|
|
53
|
+
expect(elements).toHaveLength(2);
|
|
52
54
|
});
|
|
53
55
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import CanvasListItem from '../src/CanvasListItem';
|
|
4
4
|
import AnnotationActionsContext from '../src/AnnotationActionsContext';
|
|
5
|
+
import { render, screen, fireEvent } from './test-utils';
|
|
5
6
|
|
|
6
7
|
const receiveAnnotation = jest.fn();
|
|
7
8
|
const storageAdapter = jest.fn(() => (
|
|
@@ -20,7 +21,7 @@ const storageAdapter = jest.fn(() => (
|
|
|
20
21
|
|
|
21
22
|
/** */
|
|
22
23
|
function createWrapper(props, context = {}) {
|
|
23
|
-
return
|
|
24
|
+
return render(
|
|
24
25
|
<AnnotationActionsContext.Provider
|
|
25
26
|
value={{
|
|
26
27
|
canvases: [],
|
|
@@ -44,13 +45,13 @@ function createWrapper(props, context = {}) {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
describe('CanvasListItem', () => {
|
|
47
|
-
let wrapper;
|
|
48
48
|
it('wraps its children', () => {
|
|
49
|
-
|
|
50
|
-
expect(
|
|
49
|
+
createWrapper();
|
|
50
|
+
expect(screen.getByText('HelloWorld')).toBeInTheDocument();
|
|
51
51
|
});
|
|
52
|
+
|
|
52
53
|
it('shows an edit and delete button when it matches an editable annotationid and is hovering', () => {
|
|
53
|
-
|
|
54
|
+
createWrapper({}, {
|
|
54
55
|
annotationsOnCanvases: {
|
|
55
56
|
'canv/1': {
|
|
56
57
|
'annoPage/1': {
|
|
@@ -58,6 +59,7 @@ describe('CanvasListItem', () => {
|
|
|
58
59
|
items: [
|
|
59
60
|
{
|
|
60
61
|
id: 'anno/1',
|
|
62
|
+
maeData: true,
|
|
61
63
|
},
|
|
62
64
|
],
|
|
63
65
|
},
|
|
@@ -70,23 +72,55 @@ describe('CanvasListItem', () => {
|
|
|
70
72
|
},
|
|
71
73
|
],
|
|
72
74
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
const annotationElement = screen.getAllByRole('listitem').find(
|
|
76
|
+
(el) => el.getAttribute('annotationid') === 'anno/1',
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
fireEvent.mouseEnter(annotationElement);
|
|
80
|
+
|
|
81
|
+
const buttons = screen.getAllByRole('button');
|
|
82
|
+
expect(buttons.length).toBe(3);
|
|
83
|
+
expect(screen.getByRole('button', { name: /metadata/i })).toBeInTheDocument();
|
|
84
|
+
expect(screen.getByRole('button', { name: /edit/i })).toBeInTheDocument();
|
|
85
|
+
expect(screen.getByRole('button', { name: /delete/i })).toBeInTheDocument();
|
|
75
86
|
});
|
|
87
|
+
|
|
76
88
|
it('deletes from a storageAdapter when handling deletes', async () => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
createWrapper({}, {
|
|
90
|
+
annotationEditCompanionWindowIsOpened: true,
|
|
91
|
+
annotationsOnCanvases: {
|
|
92
|
+
'canv/1': {
|
|
93
|
+
'annoPage/1': {
|
|
94
|
+
json: {
|
|
95
|
+
items: [
|
|
96
|
+
{
|
|
97
|
+
id: 'anno/1',
|
|
98
|
+
maeData: true,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
85
102
|
},
|
|
86
|
-
|
|
103
|
+
},
|
|
87
104
|
},
|
|
105
|
+
canvases: [
|
|
106
|
+
{
|
|
107
|
+
id: 'canv/1',
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const annotationElement = screen.getAllByRole('listitem').find(
|
|
113
|
+
(el) => el.getAttribute('annotationid') === 'anno/1',
|
|
114
|
+
);
|
|
115
|
+
fireEvent.mouseEnter(annotationElement);
|
|
116
|
+
|
|
117
|
+
const deleteButton = screen.getByRole('button', { name: /delete/i });
|
|
118
|
+
|
|
119
|
+
fireEvent.click(deleteButton);
|
|
120
|
+
|
|
121
|
+
expect(storageAdapter).toHaveBeenCalledTimes(1);
|
|
122
|
+
expect(storageAdapter).toHaveBeenCalledWith(
|
|
123
|
+
'canv/1',
|
|
88
124
|
);
|
|
89
|
-
await wrapper.instance().handleDelete();
|
|
90
|
-
expect(receiveAnnotation).toHaveBeenCalledWith('canvas/1', 'pageId/3', 'annoPageResultFromDelete');
|
|
91
125
|
});
|
|
92
126
|
});
|
|
@@ -1,87 +1,114 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { useDispatch } from 'react-redux';
|
|
3
|
+
|
|
4
|
+
import { getWindowViewType } from 'mirador/dist/es/src/state/selectors';
|
|
5
|
+
import LocalStorageAdapter from '../src/annotationAdapter/LocalStorageAdapter';
|
|
6
|
+
import MiradorAnnotation from '../src/plugins/miradorAnnotationPlugin';
|
|
7
|
+
import { render, screen, fireEvent } from './test-utils';
|
|
8
|
+
|
|
9
|
+
jest.mock('react-redux', () => ({
|
|
10
|
+
...jest.requireActual('react-redux'),
|
|
11
|
+
useDispatch: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
jest.mock('mirador/dist/es/src/state/selectors', () => ({
|
|
14
|
+
getWindowViewType: jest.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const defaultInitalState = {
|
|
18
|
+
config: {
|
|
19
|
+
annotation: {
|
|
20
|
+
adapter: jest.fn(),
|
|
21
|
+
exportLocalStorageAnnotations: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
6
25
|
|
|
7
26
|
/** */
|
|
8
|
-
function createWrapper(props) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
);
|
|
27
|
+
function createWrapper(props, initalState = defaultInitalState) {
|
|
28
|
+
const mockT = jest.fn().mockImplementation((key) => key);
|
|
29
|
+
|
|
30
|
+
return render(<MiradorAnnotation
|
|
31
|
+
canvases={[]}
|
|
32
|
+
config={{}}
|
|
33
|
+
TargetComponent={() => <div>hello</div>}
|
|
34
|
+
targetProps={{ windowId: 'windowId' }}
|
|
35
|
+
receiveAnnotation={jest.fn()}
|
|
36
|
+
switchToSingleCanvasView={jest.fn()}
|
|
37
|
+
annotationEditCompanionWindowIsOpened
|
|
38
|
+
t={mockT}
|
|
39
|
+
{...props}
|
|
40
|
+
/>, { preloadedState: initalState });
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
describe('MiradorAnnotation', () => {
|
|
25
|
-
let wrapper;
|
|
26
44
|
it('renders a create new button', () => {
|
|
27
|
-
|
|
28
|
-
|
|
45
|
+
createWrapper();
|
|
46
|
+
const button = screen.getByRole('button', { name: /create_annotation/i });
|
|
47
|
+
expect(button).toBeInTheDocument();
|
|
29
48
|
});
|
|
49
|
+
|
|
30
50
|
it('opens a new companionWindow when clicked', () => {
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
const mockDispatch = jest.fn();
|
|
52
|
+
useDispatch.mockImplementation(() => mockDispatch);
|
|
53
|
+
|
|
54
|
+
getWindowViewType.mockReturnValue('single');
|
|
55
|
+
createWrapper({});
|
|
56
|
+
|
|
57
|
+
const button = screen.getByRole('button', { name: /create_annotation/i });
|
|
58
|
+
fireEvent.click(button);
|
|
59
|
+
|
|
60
|
+
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
|
61
|
+
const dispatchedAction = mockDispatch.mock.calls[0][0];
|
|
62
|
+
expect(dispatchedAction).toEqual(
|
|
63
|
+
expect.objectContaining({
|
|
64
|
+
payload: expect.objectContaining({
|
|
65
|
+
content: 'annotationCreation',
|
|
66
|
+
position: 'right',
|
|
67
|
+
}),
|
|
68
|
+
type: 'mirador/ADD_COMPANION_WINDOW',
|
|
69
|
+
windowId: 'windowId',
|
|
70
|
+
}),
|
|
43
71
|
);
|
|
44
72
|
});
|
|
73
|
+
|
|
45
74
|
it('opens single canvas view dialog if not in single view', () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(
|
|
50
|
-
|
|
51
|
-
|
|
75
|
+
getWindowViewType.mockReturnValue('book');
|
|
76
|
+
createWrapper();
|
|
77
|
+
|
|
78
|
+
expect(screen.queryByText('switch_view')).toBeNull();
|
|
79
|
+
const button = screen.getByRole('button', { name: /create_annotation/i });
|
|
80
|
+
fireEvent.click(button);
|
|
81
|
+
|
|
82
|
+
expect(screen.queryByText('Switch to single view')).toBeInTheDocument();
|
|
52
83
|
});
|
|
84
|
+
|
|
53
85
|
it('renders no export button if export or LocalStorageAdapter are not configured', () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
config: {
|
|
69
|
-
annotation: {
|
|
70
|
-
adapter: (canvasId) => new LocalStorageAdapter(`test://?canvasId=${canvasId}`),
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
});
|
|
74
|
-
expect(wrapper.find(MiradorMenuButton).some({ 'aria-label': 'Export local annotations for visible items' })).toBe(false);
|
|
86
|
+
// eslint-disable-next-line max-len
|
|
87
|
+
const stateWithoutLocalAdapter = { config: { annotation: { adapter: () => () => {}, exportLocalStorageAnnotations: true } } };
|
|
88
|
+
createWrapper({}, stateWithoutLocalAdapter);
|
|
89
|
+
const button = screen.queryByText(/Export local annotations for visible items/i);
|
|
90
|
+
expect(button).toBeNull();
|
|
91
|
+
|
|
92
|
+
const annotation = {
|
|
93
|
+
adapter: () => () => {}, exportLocalStorageAnnotations: false,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const stateWithFalsyExport = { config: annotation };
|
|
97
|
+
createWrapper({}, stateWithFalsyExport);
|
|
98
|
+
const button2 = screen.queryByText(/Export local annotations for visible items/i);
|
|
99
|
+
expect(button2).toBeNull();
|
|
75
100
|
});
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
});
|
|
85
|
-
|
|
101
|
+
|
|
102
|
+
xit('renders export button if export and LocalStorageAdapter are configured', () => {
|
|
103
|
+
const annotation = {
|
|
104
|
+
adapter: () => new LocalStorageAdapter(),
|
|
105
|
+
exportLocalStorageAnnotations: true,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const initalState = { config: { annotation } };
|
|
109
|
+
createWrapper({}, initalState);
|
|
110
|
+
|
|
111
|
+
const button = screen.getByRole('button', { name: /Export local annotations for visible items/i });
|
|
112
|
+
expect(button).toBeInTheDocument();
|
|
86
113
|
});
|
|
87
114
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Provider } from 'react-redux';
|
|
3
|
+
|
|
4
|
+
import createRootReducer from 'mirador/dist/es/src/state/reducers/rootReducer';
|
|
5
|
+
import settings from 'mirador/dist/es/src/config/settings';
|
|
6
|
+
|
|
7
|
+
import { createTheme, ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
|
|
8
|
+
import { render } from '@testing-library/react';
|
|
9
|
+
import { createStore, applyMiddleware } from 'redux';
|
|
10
|
+
import { thunk } from 'redux-thunk';
|
|
11
|
+
import PropTypes from 'prop-types';
|
|
12
|
+
|
|
13
|
+
const rootReducer = createRootReducer();
|
|
14
|
+
const theme = createTheme(settings.theme);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Hook up our rendered object to redux
|
|
18
|
+
*/
|
|
19
|
+
function renderWithProviders(
|
|
20
|
+
ui,
|
|
21
|
+
{
|
|
22
|
+
preloadedState = {},
|
|
23
|
+
// Automatically create a store instance if no store was passed in
|
|
24
|
+
store = createStore(rootReducer, preloadedState, applyMiddleware(thunk)),
|
|
25
|
+
...renderOptions
|
|
26
|
+
} = {},
|
|
27
|
+
) {
|
|
28
|
+
/** :nodoc: */
|
|
29
|
+
function Wrapper({ children }) {
|
|
30
|
+
return (
|
|
31
|
+
<StyledEngineProvider injectFirst>
|
|
32
|
+
<ThemeProvider theme={theme}>
|
|
33
|
+
<Provider store={store}>{children}</Provider>
|
|
34
|
+
</ThemeProvider>
|
|
35
|
+
</StyledEngineProvider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Wrapper.propTypes = {
|
|
40
|
+
children: PropTypes.node.isRequired,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const rendered = render(ui, { wrapper: Wrapper, ...renderOptions });
|
|
44
|
+
|
|
45
|
+
// Return an object with the store and all of RTL's query functions
|
|
46
|
+
return {
|
|
47
|
+
store,
|
|
48
|
+
...rendered,
|
|
49
|
+
rerender: (newUi, options) => render(
|
|
50
|
+
newUi,
|
|
51
|
+
{ container: rendered.container, wrapper: Wrapper, ...options },
|
|
52
|
+
),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export * from '@testing-library/react';
|
|
57
|
+
export { renderWithProviders as render };
|
package/demo/src/index.js
CHANGED
|
@@ -2,19 +2,22 @@ import mirador from 'mirador/dist/es/src/index';
|
|
|
2
2
|
import annotationPlugins from '../../src';
|
|
3
3
|
import LocalStorageAdapter from '../../src/annotationAdapter/LocalStorageAdapter';
|
|
4
4
|
import { manifestsCatalog } from './manifestsCatalog';
|
|
5
|
+
import { quillConfig } from './quillConfig';
|
|
5
6
|
|
|
6
7
|
const config = {
|
|
7
8
|
annotation: {
|
|
8
9
|
adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`, 'Anonymous User'),
|
|
10
|
+
allowTargetShapesStyling: false,
|
|
9
11
|
commentTemplates: [{
|
|
12
|
+
content: '<h4>Comment</h4><p>Comment content</p>',
|
|
10
13
|
title: 'Template',
|
|
11
|
-
content: '<h4>Comment</h4><p>comment content</p>',
|
|
12
14
|
},
|
|
13
15
|
{
|
|
16
|
+
content: '<h4>Comment2</h4><p>Comment content</p>',
|
|
14
17
|
title: 'Template 2',
|
|
15
|
-
content: '<h4>Comment2</h4><p>comment content</p>',
|
|
16
18
|
}],
|
|
17
|
-
exportLocalStorageAnnotations: false,
|
|
19
|
+
exportLocalStorageAnnotations: false,
|
|
20
|
+
quillConfig,
|
|
18
21
|
tagsSuggestions: ['Mirador', 'Awesome', 'Viewer', 'IIIF', 'Template'],
|
|
19
22
|
},
|
|
20
23
|
annotations: {
|
|
@@ -66,7 +69,9 @@ const config = {
|
|
|
66
69
|
defaultSideBarPanel: 'annotations',
|
|
67
70
|
sideBarOpenByDefault: true,
|
|
68
71
|
},
|
|
69
|
-
windows: [
|
|
72
|
+
windows: [
|
|
73
|
+
{ manifestId: ' https://iiif.harvardartmuseums.org/manifests/object/299843' },
|
|
74
|
+
],
|
|
70
75
|
};
|
|
71
76
|
|
|
72
77
|
mirador.viewer(config, [...annotationPlugins]);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const quillConfig = {
|
|
2
|
+
// https://quilljs.com/docs/formats
|
|
3
|
+
formats: [
|
|
4
|
+
'header',
|
|
5
|
+
'bold',
|
|
6
|
+
'italic',
|
|
7
|
+
'underline',
|
|
8
|
+
'strike',
|
|
9
|
+
'blockquote',
|
|
10
|
+
'list',
|
|
11
|
+
'bullet',
|
|
12
|
+
'indent',
|
|
13
|
+
'link',
|
|
14
|
+
'image',
|
|
15
|
+
'color',
|
|
16
|
+
'background',
|
|
17
|
+
],
|
|
18
|
+
// https://quilljs.com/docs/modules/toolbar/
|
|
19
|
+
modules: {
|
|
20
|
+
toolbar: [
|
|
21
|
+
[{ header: [1, 2, false] }],
|
|
22
|
+
['bold', 'italic', 'underline', 'strike', 'blockquote'],
|
|
23
|
+
[
|
|
24
|
+
{ list: 'ordered' },
|
|
25
|
+
{ list: 'bullet' },
|
|
26
|
+
{ indent: '-1' },
|
|
27
|
+
{ indent: '+1' },
|
|
28
|
+
],
|
|
29
|
+
[{ color: [] }, { background: [] }],
|
|
30
|
+
['link', 'image'],
|
|
31
|
+
['clean'],
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
};
|