dbf-mirador 4.3.2 → 4.3.3
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/dist/{AudioViewer-tRH73pbt.js → AudioViewer-Cla9W2NI.js} +2 -2
- package/dist/{AudioViewer-tRH73pbt.js.map → AudioViewer-Cla9W2NI.js.map} +1 -1
- package/dist/{CommentSharp-BJ6oQAe3.js → CommentSharp-BB9dWNcO.js} +3 -3
- package/dist/{CommentSharp-BJ6oQAe3.js.map → CommentSharp-BB9dWNcO.js.map} +1 -1
- package/dist/{FailedImageContext-BhA0TpVp.js → FailedImageContext-C-8e4l3r.js} +14 -8
- package/dist/FailedImageContext-C-8e4l3r.js.map +1 -0
- package/dist/{GalleryView-rCx0Q4f3.js → GalleryView-BS7q2lC0.js} +5 -5
- package/dist/{GalleryView-rCx0Q4f3.js.map → GalleryView-BS7q2lC0.js.map} +1 -1
- package/dist/{OpenSeadragonViewer-4nw8qaVM.js → OpenSeadragonViewer-DtalKKE4.js} +312 -293
- package/dist/{OpenSeadragonViewer-4nw8qaVM.js.map → OpenSeadragonViewer-DtalKKE4.js.map} +1 -1
- package/dist/{TextViewer-D_1qzQE4.js → TextViewer-Dn04175s.js} +3 -3
- package/dist/{TextViewer-D_1qzQE4.js.map → TextViewer-Dn04175s.js.map} +1 -1
- package/dist/{VideoViewer-DzNjgLWE.js → VideoViewer-Db17A1Pj.js} +2 -2
- package/dist/{VideoViewer-DzNjgLWE.js.map → VideoViewer-Db17A1Pj.js.map} +1 -1
- package/dist/{WindowCanvasNavigationControls-D2uLtL_A.js → WindowCanvasNavigationControls-BEfgwEVZ.js} +3 -3
- package/dist/{WindowCanvasNavigationControls-D2uLtL_A.js.map → WindowCanvasNavigationControls-BEfgwEVZ.js.map} +1 -1
- package/dist/{WindowViewer-uHVYcMsX.js → WindowViewer-Bwx-8xYM.js} +3 -3
- package/dist/{WindowViewer-uHVYcMsX.js.map → WindowViewer-Bwx-8xYM.js.map} +1 -1
- package/dist/{WorkspaceArea-7bydz9m-.js → WorkspaceArea-SpTGn3q2.js} +4019 -3998
- package/dist/WorkspaceArea-SpTGn3q2.js.map +1 -0
- package/dist/{canvas-2ACcnS9Y.js → canvas-CnyCCdkT.js} +2 -2
- package/dist/{canvas-2ACcnS9Y.js.map → canvas-CnyCCdkT.js.map} +1 -1
- package/dist/{canvases-DTR37lo-.js → canvases-Bxeg1axY.js} +255 -255
- package/dist/{canvases-DTR37lo-.js.map → canvases-Bxeg1axY.js.map} +1 -1
- package/dist/{index.module-CgUBfaXx.js → index.module-BYoozchK.js} +7 -7
- package/dist/{index.module-CgUBfaXx.js.map → index.module-BYoozchK.js.map} +1 -1
- package/dist/mirador.es.js +1593 -1446
- package/dist/mirador.es.js.map +1 -1
- package/dist/mirador.min.js +30 -27
- package/dist/mirador.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AnnotationsOverlay.jsx +28 -1
- package/src/components/CompanionWindow.jsx +39 -2
- package/src/components/MapViewer.jsx +77 -4
- package/src/lib/AnnotationItem.js +5 -0
- package/src/lib/AnnotationResource.js +5 -0
- package/src/lib/CanvasAnnotationDisplay.js +52 -14
- package/src/plugins/index.js +1 -0
- package/src/plugins/nestedMapPlugin.tsx +152 -0
- package/src/plugins/poiPreviewPlugin.tsx +256 -77
- package/dist/FailedImageContext-BhA0TpVp.js.map +0 -1
- package/dist/WorkspaceArea-7bydz9m-.js.map +0 -1
|
@@ -1,19 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, type ComponentType } from 'react';
|
|
2
|
+
import Button from '@mui/material/Button';
|
|
3
|
+
import MapIcon from '@mui/icons-material/MapSharp';
|
|
2
4
|
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
3
5
|
import { useTheme } from '@mui/material/styles';
|
|
6
|
+
import OpenSeadragon from 'openseadragon';
|
|
4
7
|
import {
|
|
8
|
+
AnnotationItem,
|
|
5
9
|
ConnectedCompanionWindow as CompanionWindow,
|
|
10
|
+
OSDReferences,
|
|
6
11
|
addCompanionWindow,
|
|
7
12
|
getAnnotations,
|
|
8
13
|
getCompanionWindow,
|
|
9
14
|
getCompanionWindows,
|
|
15
|
+
getConfig,
|
|
16
|
+
getSelectedAnnotationId,
|
|
10
17
|
getVisibleCanvases,
|
|
18
|
+
selectAnnotation,
|
|
11
19
|
updateCompanionWindow,
|
|
12
20
|
// Relative, not `from 'dbf-mirador'`: this file lives inside the dbf-mirador package
|
|
13
21
|
// itself (unlike its copy in the Strapi maps plugin, a real external consumer), and
|
|
14
22
|
// there's no self-referencing node_modules link or dist build for the package name to
|
|
15
23
|
// resolve against during local dev.
|
|
16
24
|
} from '../index';
|
|
25
|
+
import { getLinkedMapManifestId, openNestedMap, type LinkedMap } from './nestedMapPlugin';
|
|
17
26
|
|
|
18
27
|
// A "dumb" way to preview a POI/journey (issue #375): a Mirador companion window plugin,
|
|
19
28
|
// registered alongside dbf-mirador-annotation-editor's own (see MiradorMaeViewer.tsx) via
|
|
@@ -24,9 +33,8 @@ import {
|
|
|
24
33
|
// specific row's id as `annotationid`, the same convention MAE's own 'annotationCreation'
|
|
25
34
|
// companion window already uses for its own Edit button.
|
|
26
35
|
//
|
|
27
|
-
// Journeys (issue #378) get a richer path here:
|
|
28
|
-
//
|
|
29
|
-
// locale (toggle EN/AR), closer to how the public site will eventually present it. Two
|
|
36
|
+
// Journeys (issue #378) get a richer path here: a Journey renders its ordered stops as
|
|
37
|
+
// numbered cards, closer to how the public site will eventually present it. Two
|
|
30
38
|
// pieces of the Figma design are intentionally NOT built here, per the issue author's own
|
|
31
39
|
// follow-up comment saying they "wait more precision": numbered pins drawn on the map
|
|
32
40
|
// canvas itself, and an SVG line joining those pins in journey order.
|
|
@@ -61,13 +69,42 @@ type RawAnnotation = {
|
|
|
61
69
|
// annotationListGrouping.js, which this plugin can't import directly since grouping
|
|
62
70
|
// isn't part of that package's public API - so the same filter+sort is redone below).
|
|
63
71
|
'dbf:journey'?: { id: string; order: number } | null;
|
|
72
|
+
// Set on a "Nested Map" point only: the map it opens (see nestedMapPlugin.tsx).
|
|
73
|
+
'dbf:linkedMap'?: LinkedMap | null;
|
|
64
74
|
body?: TextualAnnotationBody[];
|
|
75
|
+
target?: unknown;
|
|
65
76
|
};
|
|
66
77
|
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
|
|
78
|
+
// Content is authored in English and Arabic only. The preview shows the one matching
|
|
79
|
+
// Mirador's own UI language (`config.language`, which MapViewer's `lang` prop sets), so a
|
|
80
|
+
// map and its previews always speak the same language - Arabic for any `ar*` language,
|
|
81
|
+
// English otherwise.
|
|
82
|
+
export type ContentLocale = 'en' | 'ar';
|
|
83
|
+
export const getContentLocale = (language?: string | null): ContentLocale =>
|
|
84
|
+
(language ?? '').split('-')[0].toLowerCase() === 'ar' ? 'ar' : 'en';
|
|
85
|
+
|
|
86
|
+
// The preview's own UI strings - a local table rather than Mirador's i18n resources, since
|
|
87
|
+
// only the two content locales ever reach this plugin.
|
|
88
|
+
const LABELS: Record<ContentLocale, Record<string, string>> = {
|
|
89
|
+
ar: {
|
|
90
|
+
Journey: 'رحلة',
|
|
91
|
+
POI: 'نقطة اهتمام',
|
|
92
|
+
noStops: 'لا توجد محطات في هذه الرحلة بعد.',
|
|
93
|
+
notFound: 'تعذر العثور على هذا العنصر - ربما تم حذفه.',
|
|
94
|
+
openMap: 'فتح الخريطة',
|
|
95
|
+
preview: 'معاينة',
|
|
96
|
+
showOnMap: 'عرض على الخريطة',
|
|
97
|
+
},
|
|
98
|
+
en: {
|
|
99
|
+
Journey: 'Journey',
|
|
100
|
+
POI: 'POI',
|
|
101
|
+
noStops: 'This journey has no stops yet.',
|
|
102
|
+
notFound: 'This annotation could not be found - it may have been deleted.',
|
|
103
|
+
openMap: 'Open map',
|
|
104
|
+
preview: 'Preview',
|
|
105
|
+
showOnMap: 'Show on map',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
71
108
|
|
|
72
109
|
const textBody = (
|
|
73
110
|
annotation: RawAnnotation,
|
|
@@ -79,7 +116,7 @@ const textBody = (
|
|
|
79
116
|
item.type === 'TextualBody' && item.purpose === purpose && item.language === language
|
|
80
117
|
)?.value ?? '';
|
|
81
118
|
|
|
82
|
-
const mediaForLocale = (annotation: RawAnnotation, locale:
|
|
119
|
+
const mediaForLocale = (annotation: RawAnnotation, locale: ContentLocale): DbfMedia | null | undefined =>
|
|
83
120
|
locale === 'en' ? annotation['dbf:mediaEn'] : annotation['dbf:mediaAr'];
|
|
84
121
|
|
|
85
122
|
// A journey's ordered stops, derived the same way the rest of the codebase does: every
|
|
@@ -92,55 +129,144 @@ export const getOrderedJourneyPois = (items: RawAnnotation[], journeyId: string)
|
|
|
92
129
|
)
|
|
93
130
|
.sort((a, b) => a['dbf:journey'].order - b['dbf:journey'].order);
|
|
94
131
|
|
|
95
|
-
|
|
96
|
-
|
|
132
|
+
// A POI's pin position, in canvas coordinates - the same PointSelector AnnotationsOverlay
|
|
133
|
+
// draws the pin from. The map viewer shows a single canvas, so canvas coordinates are also
|
|
134
|
+
// OpenSeadragon's viewport coordinates (a multi-canvas layout would need CanvasWorld's offset).
|
|
135
|
+
type Point = { x: number; y: number };
|
|
136
|
+
export const getPoiPoint = (poi: RawAnnotation): Point | null => {
|
|
137
|
+
// AnnotationItem#pointSelector throws on a target-less annotation (its selector is `null`)
|
|
138
|
+
if (!poi.target) return null;
|
|
139
|
+
const selector = new AnnotationItem(poi).pointSelector as Partial<Point> | null | undefined;
|
|
140
|
+
if (typeof selector?.x !== 'number' || typeof selector?.y !== 'number') return null;
|
|
141
|
+
return { x: selector.x, y: selector.y };
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// How far "focus on this stop" zooms in, relative to the whole-map (home) zoom - a ratio
|
|
145
|
+
// rather than an absolute zoom, since Mirador's viewport is in canvas pixels so absolute
|
|
146
|
+
// zoom levels differ from one map to another.
|
|
147
|
+
const POI_FOCUS_ZOOM_RATIO = 4;
|
|
148
|
+
// Margin kept around a journey's stops when fitting them all in view, as a fraction of the
|
|
149
|
+
// stops' own bounding box (with a floor for journeys whose stops are almost on top of each other).
|
|
150
|
+
const JOURNEY_FIT_PADDING_RATIO = 0.2;
|
|
151
|
+
|
|
152
|
+
const getOsdViewer = (windowId: string) =>
|
|
153
|
+
OSDReferences.get(windowId)?.current ?? null;
|
|
154
|
+
|
|
155
|
+
// Pans the main map onto a point, zooming in if the map is further out than the focus zoom
|
|
156
|
+
// (but never zooming out a user who is already closer in).
|
|
157
|
+
export const focusMapOnPoint = (windowId: string, point: Point) => {
|
|
158
|
+
const viewport = getOsdViewer(windowId)?.viewport;
|
|
159
|
+
if (!viewport) return;
|
|
160
|
+
|
|
161
|
+
const center = new OpenSeadragon.Point(point.x, point.y);
|
|
162
|
+
const zoom = Math.min(
|
|
163
|
+
viewport.getMaxZoom(),
|
|
164
|
+
Math.max(viewport.getZoom(), viewport.getHomeZoom() * POI_FOCUS_ZOOM_RATIO)
|
|
165
|
+
);
|
|
166
|
+
viewport.panTo(center);
|
|
167
|
+
viewport.zoomTo(zoom, center);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Fits every stop of a journey in view at once.
|
|
171
|
+
export const fitMapToPoints = (windowId: string, points: Point[]) => {
|
|
172
|
+
if (points.length === 0) return;
|
|
173
|
+
if (points.length === 1) {
|
|
174
|
+
focusMapOnPoint(windowId, points[0]);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const viewport = getOsdViewer(windowId)?.viewport;
|
|
179
|
+
if (!viewport) return;
|
|
97
180
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
181
|
+
const xs = points.map(({ x }) => x);
|
|
182
|
+
const ys = points.map(({ y }) => y);
|
|
183
|
+
const minX = Math.min(...xs);
|
|
184
|
+
const minY = Math.min(...ys);
|
|
185
|
+
const width = Math.max(...xs) - minX;
|
|
186
|
+
const height = Math.max(...ys) - minY;
|
|
187
|
+
const home = viewport.getHomeBounds();
|
|
188
|
+
const padX = Math.max(width * JOURNEY_FIT_PADDING_RATIO, home.width * 0.05);
|
|
189
|
+
const padY = Math.max(height * JOURNEY_FIT_PADDING_RATIO, home.height * 0.05);
|
|
190
|
+
|
|
191
|
+
viewport.fitBoundsWithConstraints(
|
|
192
|
+
new OpenSeadragon.Rect(minX - padX, minY - padY, width + 2 * padX, height + 2 * padY)
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const localeDir = (locale: ContentLocale) => (locale === 'ar' ? 'rtl' : 'ltr');
|
|
101
197
|
|
|
102
198
|
interface JourneyPreviewContentProps {
|
|
103
199
|
id: string;
|
|
104
200
|
journey: RawAnnotation;
|
|
201
|
+
locale: ContentLocale;
|
|
105
202
|
pois: RawAnnotation[];
|
|
203
|
+
selectAnnotation: typeof selectAnnotation;
|
|
204
|
+
selectedAnnotationId?: string;
|
|
106
205
|
windowId: string;
|
|
107
206
|
}
|
|
108
207
|
|
|
109
|
-
const JourneyPreviewContent = ({
|
|
110
|
-
|
|
208
|
+
const JourneyPreviewContent = ({
|
|
209
|
+
id,
|
|
210
|
+
journey,
|
|
211
|
+
locale,
|
|
212
|
+
pois,
|
|
213
|
+
selectAnnotation: dispatchSelectAnnotation,
|
|
214
|
+
selectedAnnotationId,
|
|
215
|
+
windowId,
|
|
216
|
+
}: JourneyPreviewContentProps) => {
|
|
217
|
+
const labels = LABELS[locale];
|
|
111
218
|
const journeyTitle = textBody(journey, locale, 'identifying');
|
|
112
219
|
|
|
220
|
+
// `pois` is a fresh array on every store update, so the fit below is keyed on the stops'
|
|
221
|
+
// actual positions instead - it only re-runs when another journey is previewed or a stop moves.
|
|
222
|
+
const points = pois.map(getPoiPoint).filter((point): point is Point => point !== null);
|
|
223
|
+
const pointsKey = points.map(({ x, y }) => `${x},${y}`).join(';');
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
fitMapToPoints(windowId, points);
|
|
226
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- `points` is captured by `pointsKey`
|
|
227
|
+
}, [journey.id, pointsKey, windowId]);
|
|
228
|
+
|
|
229
|
+
const focusPoi = (poi: RawAnnotation) => {
|
|
230
|
+
const point = getPoiPoint(poi);
|
|
231
|
+
if (point) focusMapOnPoint(windowId, point);
|
|
232
|
+
// Selecting it also highlights the pin on the map, like clicking the pin itself would.
|
|
233
|
+
dispatchSelectAnnotation(windowId, poi.id);
|
|
234
|
+
};
|
|
235
|
+
|
|
113
236
|
return (
|
|
114
|
-
<CompanionWindow id={id} title={journeyTitle ||
|
|
115
|
-
<div dir={
|
|
116
|
-
|
|
117
|
-
{JOURNEY_PREVIEW_LOCALES.map((code) => (
|
|
118
|
-
<button
|
|
119
|
-
aria-pressed={locale === code}
|
|
120
|
-
key={code}
|
|
121
|
-
onClick={() => setLocale(code)}
|
|
122
|
-
style={{
|
|
123
|
-
background: locale === code ? '#333' : 'transparent',
|
|
124
|
-
border: '1px solid #333',
|
|
125
|
-
borderRadius: 4,
|
|
126
|
-
color: locale === code ? '#fff' : '#333',
|
|
127
|
-
cursor: 'pointer',
|
|
128
|
-
padding: '4px 12px',
|
|
129
|
-
}}
|
|
130
|
-
type="button"
|
|
131
|
-
>
|
|
132
|
-
{code.toUpperCase()}
|
|
133
|
-
</button>
|
|
134
|
-
))}
|
|
135
|
-
</div>
|
|
136
|
-
{pois.length === 0 && <p>This journey has no stops yet.</p>}
|
|
237
|
+
<CompanionWindow id={id} title={journeyTitle || labels.Journey} windowId={windowId}>
|
|
238
|
+
<div dir={localeDir(locale)} lang={locale} style={{ padding: 16 }}>
|
|
239
|
+
{pois.length === 0 && <p>{labels.noStops}</p>}
|
|
137
240
|
{pois.map((poi, index) => {
|
|
138
241
|
const poiTitle = textBody(poi, locale, 'identifying');
|
|
139
242
|
const description = textBody(poi, locale, 'describing');
|
|
140
243
|
const media = mediaForLocale(poi, locale);
|
|
141
244
|
const isLast = index === pois.length - 1;
|
|
245
|
+
const isSelected = poi.id === selectedAnnotationId;
|
|
142
246
|
return (
|
|
143
|
-
<div
|
|
247
|
+
<div
|
|
248
|
+
aria-current={isSelected || undefined}
|
|
249
|
+
key={poi.id}
|
|
250
|
+
onClick={() => focusPoi(poi)}
|
|
251
|
+
onKeyDown={(event) => {
|
|
252
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
253
|
+
event.preventDefault();
|
|
254
|
+
focusPoi(poi);
|
|
255
|
+
}
|
|
256
|
+
}}
|
|
257
|
+
role="button"
|
|
258
|
+
style={{
|
|
259
|
+
background: isSelected ? 'rgba(0, 0, 0, 0.06)' : undefined,
|
|
260
|
+
borderRadius: 8,
|
|
261
|
+
cursor: 'pointer',
|
|
262
|
+
display: 'flex',
|
|
263
|
+
marginInline: -8,
|
|
264
|
+
paddingInline: 8,
|
|
265
|
+
paddingTop: 8,
|
|
266
|
+
}}
|
|
267
|
+
tabIndex={0}
|
|
268
|
+
title={labels.showOnMap}
|
|
269
|
+
>
|
|
144
270
|
<div
|
|
145
271
|
style={{
|
|
146
272
|
alignItems: 'center',
|
|
@@ -194,56 +320,104 @@ const JourneyPreviewContent = ({ id, journey, pois, windowId }: JourneyPreviewCo
|
|
|
194
320
|
interface PoiPreviewContentProps {
|
|
195
321
|
annotation: RawAnnotation | null;
|
|
196
322
|
id: string;
|
|
323
|
+
linkedMapManifestId: string | null;
|
|
324
|
+
locale: ContentLocale;
|
|
325
|
+
openNestedMap: (windowId: string, manifestId: string) => void;
|
|
197
326
|
windowId: string;
|
|
198
327
|
}
|
|
199
328
|
|
|
200
|
-
const PoiPreviewContent = ({
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
)
|
|
329
|
+
const PoiPreviewContent = ({
|
|
330
|
+
annotation,
|
|
331
|
+
id,
|
|
332
|
+
linkedMapManifestId,
|
|
333
|
+
locale,
|
|
334
|
+
openNestedMap: dispatchOpenNestedMap,
|
|
335
|
+
windowId,
|
|
336
|
+
}: PoiPreviewContentProps) => {
|
|
337
|
+
const labels = LABELS[locale];
|
|
338
|
+
const kind = annotation?.['dbf:kind'];
|
|
339
|
+
const title = annotation ? textBody(annotation, locale, 'identifying') : '';
|
|
340
|
+
const description = annotation ? textBody(annotation, locale, 'describing') : '';
|
|
341
|
+
const media = annotation ? mediaForLocale(annotation, locale) : null;
|
|
342
|
+
|
|
343
|
+
return (
|
|
344
|
+
<CompanionWindow id={id} title={title || (kind && labels[kind]) || labels.preview} windowId={windowId}>
|
|
345
|
+
<div dir={localeDir(locale)} lang={locale} style={{ padding: 16 }}>
|
|
346
|
+
{!annotation && <p>{labels.notFound}</p>}
|
|
347
|
+
{description && (
|
|
348
|
+
// eslint-disable-next-line react/no-danger -- descriptionEn/Ar is CKEditor HTML, the same content the public site will eventually render
|
|
349
|
+
<div dangerouslySetInnerHTML={{ __html: description }} />
|
|
350
|
+
)}
|
|
351
|
+
{media &&
|
|
352
|
+
(media.thumbnailUrl ? (
|
|
353
|
+
<img alt={media.title ?? ''} src={media.thumbnailUrl} style={{ maxWidth: '100%' }} />
|
|
354
|
+
) : (
|
|
355
|
+
<p>
|
|
356
|
+
{media.title}
|
|
357
|
+
{media.mediaType ? ` (${media.mediaType})` : ''}
|
|
358
|
+
</p>
|
|
359
|
+
))}
|
|
360
|
+
{linkedMapManifestId && (
|
|
361
|
+
<Button
|
|
362
|
+
onClick={() => dispatchOpenNestedMap(windowId, linkedMapManifestId)}
|
|
363
|
+
startIcon={<MapIcon />}
|
|
364
|
+
sx={{ marginTop: 2 }}
|
|
365
|
+
variant="contained"
|
|
366
|
+
>
|
|
367
|
+
{labels.openMap}
|
|
368
|
+
</Button>
|
|
369
|
+
)}
|
|
370
|
+
</div>
|
|
371
|
+
</CompanionWindow>
|
|
372
|
+
);
|
|
373
|
+
};
|
|
234
374
|
|
|
235
375
|
interface PreviewContentProps {
|
|
236
376
|
annotation: RawAnnotation | null;
|
|
237
377
|
id: string;
|
|
238
378
|
journeyPois: RawAnnotation[];
|
|
379
|
+
linkedMapManifestId: string | null;
|
|
380
|
+
locale: ContentLocale;
|
|
381
|
+
openNestedMap: (windowId: string, manifestId: string) => void;
|
|
382
|
+
selectAnnotation: typeof selectAnnotation;
|
|
383
|
+
selectedAnnotationId?: string;
|
|
239
384
|
windowId: string;
|
|
240
385
|
}
|
|
241
386
|
|
|
242
|
-
const PreviewContent = ({
|
|
387
|
+
const PreviewContent = ({
|
|
388
|
+
annotation,
|
|
389
|
+
id,
|
|
390
|
+
journeyPois,
|
|
391
|
+
linkedMapManifestId,
|
|
392
|
+
locale,
|
|
393
|
+
openNestedMap: dispatchOpenNestedMap,
|
|
394
|
+
selectAnnotation: dispatchSelectAnnotation,
|
|
395
|
+
selectedAnnotationId,
|
|
396
|
+
windowId,
|
|
397
|
+
}: PreviewContentProps) => {
|
|
243
398
|
if (annotation && annotation['dbf:kind'] === 'Journey') {
|
|
244
|
-
return
|
|
399
|
+
return (
|
|
400
|
+
<JourneyPreviewContent
|
|
401
|
+
id={id}
|
|
402
|
+
journey={annotation}
|
|
403
|
+
locale={locale}
|
|
404
|
+
pois={journeyPois}
|
|
405
|
+
selectAnnotation={dispatchSelectAnnotation}
|
|
406
|
+
selectedAnnotationId={selectedAnnotationId}
|
|
407
|
+
windowId={windowId}
|
|
408
|
+
/>
|
|
409
|
+
);
|
|
245
410
|
}
|
|
246
|
-
return
|
|
411
|
+
return (
|
|
412
|
+
<PoiPreviewContent
|
|
413
|
+
annotation={annotation}
|
|
414
|
+
id={id}
|
|
415
|
+
linkedMapManifestId={linkedMapManifestId}
|
|
416
|
+
locale={locale}
|
|
417
|
+
openNestedMap={dispatchOpenNestedMap}
|
|
418
|
+
windowId={windowId}
|
|
419
|
+
/>
|
|
420
|
+
);
|
|
247
421
|
};
|
|
248
422
|
|
|
249
423
|
const poiPreviewCompanionWindowPlugin = {
|
|
@@ -265,8 +439,13 @@ const poiPreviewCompanionWindowPlugin = {
|
|
|
265
439
|
annotation,
|
|
266
440
|
journeyPois:
|
|
267
441
|
annotation && annotation['dbf:kind'] === 'Journey' ? getOrderedJourneyPois(items, annotation.id) : [],
|
|
442
|
+
// Only a Nested Map point whose map the host can resolve gets an "Open map" button.
|
|
443
|
+
linkedMapManifestId: getLinkedMapManifestId(state, annotation?.['dbf:linkedMap']),
|
|
444
|
+
locale: getContentLocale((getConfig(state) as { language?: string }).language),
|
|
445
|
+
selectedAnnotationId: getSelectedAnnotationId(state, { windowId }) as string | undefined,
|
|
268
446
|
};
|
|
269
447
|
},
|
|
448
|
+
mapDispatchToProps: { openNestedMap, selectAnnotation },
|
|
270
449
|
};
|
|
271
450
|
|
|
272
451
|
// A canvas annotation resource, as AnnotationsOverlay's own `annotations`/`searchAnnotations`
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FailedImageContext-BhA0TpVp.js","names":[],"sources":["../node_modules/lodash/_baseFilter.js","../node_modules/lodash/filter.js","../node_modules/lodash/compact.js","../src/lib/AnnotationResource.js","../src/lib/AnnotationList.js","../src/lib/AnnotationItem.js","../src/lib/AnnotationPage.js","../src/lib/AnnotationFactory.js","../src/state/selectors/annotations.js","../src/state/selectors/searches.js","../src/state/actions/annotation.js","../src/contexts/FailedImageContext.js"],"sourcesContent":["var baseEach = require('./_baseEach');\n\n/**\n * The base implementation of `_.filter` without support for iteratee shorthands.\n *\n * @private\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction baseFilter(collection, predicate) {\n var result = [];\n baseEach(collection, function(value, index, collection) {\n if (predicate(value, index, collection)) {\n result.push(value);\n }\n });\n return result;\n}\n\nmodule.exports = baseFilter;\n","var arrayFilter = require('./_arrayFilter'),\n baseFilter = require('./_baseFilter'),\n baseIteratee = require('./_baseIteratee'),\n isArray = require('./isArray');\n\n/**\n * Iterates over elements of `collection`, returning an array of all elements\n * `predicate` returns truthy for. The predicate is invoked with three\n * arguments: (value, index|key, collection).\n *\n * **Note:** Unlike `_.remove`, this method returns a new array.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Collection\n * @param {Array|Object} collection The collection to iterate over.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n * @see _.reject\n * @example\n *\n * var users = [\n * { 'user': 'barney', 'age': 36, 'active': true },\n * { 'user': 'fred', 'age': 40, 'active': false }\n * ];\n *\n * _.filter(users, function(o) { return !o.active; });\n * // => objects for ['fred']\n *\n * // The `_.matches` iteratee shorthand.\n * _.filter(users, { 'age': 36, 'active': true });\n * // => objects for ['barney']\n *\n * // The `_.matchesProperty` iteratee shorthand.\n * _.filter(users, ['active', false]);\n * // => objects for ['fred']\n *\n * // The `_.property` iteratee shorthand.\n * _.filter(users, 'active');\n * // => objects for ['barney']\n *\n * // Combining several predicates using `_.overEvery` or `_.overSome`.\n * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));\n * // => objects for ['fred', 'barney']\n */\nfunction filter(collection, predicate) {\n var func = isArray(collection) ? arrayFilter : baseFilter;\n return func(collection, baseIteratee(predicate, 3));\n}\n\nmodule.exports = filter;\n","/**\n * Creates an array with all falsey values removed. The values `false`, `null`,\n * `0`, `-0`, `0n`, `\"\"`, `undefined`, and `NaN` are falsy.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to compact.\n * @returns {Array} Returns the new array of filtered values.\n * @example\n *\n * _.compact([0, 1, false, 2, '', 3]);\n * // => [1, 2, 3]\n */\nfunction compact(array) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (value) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nmodule.exports = compact;\n","import compact from 'lodash/compact';\nimport { v4 as uuid } from 'uuid';\n\n/** */\nexport default class AnnotationResource {\n /** */\n constructor(resource = {}) {\n this.resource = resource;\n }\n\n /** */\n isOnlyTag() {\n return this.motivations.length === 1 && this.motivations[0] === 'oa:tagging';\n }\n\n /** */\n get id() {\n this._id = this._id || this.resource['@id'] || (this.resources[0] && this.resources[0]['@id']) || uuid();\n return this._id;\n }\n\n /** */\n get targetId() {\n const on = this.on[0];\n switch (typeof on) {\n case 'string':\n return on.replace(/#?xywh=(.*)$/, '');\n case 'object':\n return on.full.replace(/#?xywh=(.*)$/, '');\n default:\n return null;\n }\n }\n\n /**\n * @return {[Array]}\n */\n get motivations() {\n return compact(new Array(this.resource.motivation)).flat();\n }\n\n /** */\n get resources() {\n return compact(new Array(this.resource.resource)).flat();\n }\n\n /** */\n get on() {\n return compact(new Array(this.resource.on)).flat();\n }\n\n /** */\n get tags() {\n if (this.isOnlyTag()) {\n return this.resources.map((r) => r.chars);\n }\n return this.resources.filter((r) => r['@type'] === 'oa:Tag').map((r) => r.chars);\n }\n\n /** */\n get chars() {\n return this.resources\n .filter((r) => r['@type'] !== 'oa:Tag')\n .map((r) => r.chars)\n .join(' ');\n }\n\n /** */\n get selector() {\n const on = this.on[0];\n switch (typeof on) {\n case 'string':\n return on;\n case 'object':\n // For choices, just return the default for now. FIXME: enhance for SVG\n // selectors\n if (on.selector['@type'] === 'oa:Choice') {\n return on.selector.default;\n }\n return on.selector;\n default:\n return null;\n }\n }\n\n /** */\n get svgSelector() {\n const on = this.on[0];\n\n switch (typeof on) {\n case 'string':\n return null;\n case 'object':\n if (on.selector && on.selector.item && on.selector.item['@type'] === 'oa:SvgSelector') {\n return on.selector.item;\n }\n return null;\n default:\n return null;\n }\n }\n\n /** */\n get fragmentSelector() {\n const { selector } = this;\n\n let match;\n\n switch (typeof selector) {\n case 'string':\n match = selector.match(/xywh=(.*)$/);\n break;\n case 'object':\n match = selector.value.match(/xywh=(.*)$/);\n break;\n default:\n return null;\n }\n\n return match && match[1].split(',').map((str) => parseInt(str, 10));\n }\n\n /** */\n get pointSelector() {\n const { selector } = this;\n if (selector && typeof selector === 'object' && selector['@type'] === 'oa:PointSelector') {\n return { x: selector.x, y: selector.y };\n }\n return null;\n }\n\n /** the POI's position within its journey (see mirador-annotation-editor's `dbf:journey`), or null when the POI is not part of a journey */\n get journeyOrder() {\n return this.resource['dbf:journey']?.order ?? null;\n }\n}\n","import AnnotationResource from './AnnotationResource';\n/** */\nexport default class AnnotationList {\n /** */\n constructor(json, target) {\n this.json = json;\n this.target = target;\n }\n\n /** */\n get id() {\n return this.json['@id'];\n }\n\n /** */\n present() {\n return this.resources && this.resources.length > 0;\n }\n\n /** */\n get resources() {\n this._resources =\n this._resources ||\n (() => {\n if (!this.json || !this.json.resources) return [];\n\n return [this.json.resources].flat().map((resource) => new AnnotationResource(resource));\n })();\n return this._resources;\n }\n}\n","import compact from 'lodash/compact';\nimport { v4 as uuid } from 'uuid';\n\n/**\n * A modeled WebAnnotation item\n */\nexport default class AnnotationItem {\n /** */\n constructor(resource = {}) {\n this.resource = resource;\n }\n\n /** */\n isOnlyTag() {\n return this.motivations.length === 1 && this.motivations[0] === 'tagging';\n }\n\n /** */\n get id() {\n this._id = this._id || this.resource.id || uuid();\n return this._id;\n }\n\n /** */\n get targetId() {\n const target = this.target[0];\n switch (typeof target) {\n case 'string':\n return target.replace(/#?xywh=(.*)$/, '');\n case 'object':\n return (target.source && target.source.id) || target.source || target.id;\n default:\n return null;\n }\n }\n\n /**\n * @return {[Array]}\n */\n get motivations() {\n return compact(new Array(this.resource.motivation)).flat();\n }\n\n /** */\n get body() {\n return compact(new Array(this.resource.body)).flat();\n }\n\n /** */\n get resources() {\n return this.body;\n }\n\n /** */\n get tags() {\n if (this.isOnlyTag()) {\n return this.body.map((r) => r.value);\n }\n return this.body.filter((r) => r.purpose === 'tagging').map((r) => r.value);\n }\n\n /** */\n get target() {\n return compact(new Array(this.resource.target)).flat();\n }\n\n /** */\n get chars() {\n if (this.isOnlyTag()) return null;\n return this.body\n .filter((r) => r.purpose !== 'tagging')\n .map((r) => r.value)\n .join(' ');\n }\n\n /** */\n get selector() {\n const target = this.target[0];\n switch (typeof target) {\n case 'string':\n return target;\n case 'object':\n return compact(new Array(target.selector)).flat();\n default:\n return null;\n }\n }\n\n /** */\n get svgSelector() {\n const { selector } = this;\n switch (typeof selector) {\n case 'string':\n return null;\n case 'object':\n return selector.find((s) => s.type && s.type === 'SvgSelector');\n default:\n return null;\n }\n }\n\n /** */\n get fragmentSelector() {\n const { selector } = this;\n\n let match;\n let fragmentSelector;\n\n switch (typeof selector) {\n case 'string':\n match = selector.match(/xywh=(.*)$/);\n break;\n case 'object':\n fragmentSelector = selector.find((s) => s.type && s.type === 'FragmentSelector');\n match = fragmentSelector && fragmentSelector.value.match(/xywh=(.*)$/);\n break;\n default:\n return null;\n }\n\n return match && match[1].split(',').map((str) => parseInt(str, 10));\n }\n\n /** */\n get pointSelector() {\n const { selector } = this;\n switch (typeof selector) {\n case 'string':\n return null;\n case 'object':\n return selector.find((s) => s.type && s.type === 'PointSelector');\n default:\n return null;\n }\n }\n\n /** the POI's position within its journey (see mirador-annotation-editor's `dbf:journey`), or null when the POI is not part of a journey */\n get journeyOrder() {\n return this.resource['dbf:journey']?.order ?? null;\n }\n}\n","import AnnotationItem from './AnnotationItem';\n/**\n * Annotation representation for IIIF Presentation v3\n * https://iiif.io/api/presentation/3.0/#55-annotation-page\n */\nexport default class AnnotationPage {\n /** */\n constructor(json, target) {\n this.json = json;\n this.target = target;\n }\n\n /** */\n get id() {\n return this.json.id;\n }\n\n /** */\n present() {\n return this.items && this.items.length > 0;\n }\n\n /** */\n get items() {\n this._items =\n this._items ||\n (() => {\n if (!this.json || !this.json.items) return [];\n\n return [this.json.items].flat().map((resource) => new AnnotationItem(resource));\n })();\n return this._items;\n }\n\n /**\n * Alias to items for compatibility for right now.\n */\n get resources() {\n return this.items;\n }\n}\n","import AnnotationList from './AnnotationList';\nimport AnnotationPage from './AnnotationPage';\n\n/**\n * Used to determine the type of Annotation supported by a version of the IIIF\n * Presentation API.\n */\nexport default class AnnotationFactory {\n /** */\n static determineAnnotation(json, target) {\n if (!json) {\n return null;\n }\n\n // IIIF Presentation API v3. AnnotationPage\n if (json.type === 'AnnotationPage') {\n return new AnnotationPage(json, target);\n }\n\n // IIIF Presentation API v2. OpenAnnotation and SharedCanvas models\n return new AnnotationList(json, target);\n }\n}\n","import { createSelector } from 'reselect';\nimport filter from 'lodash/filter';\nimport AnnotationFactory from '../../lib/AnnotationFactory';\nimport { miradorSlice } from './utils';\nimport { getCanvas, getVisibleCanvasIds } from './canvases';\nimport { getConfig } from './config';\nimport { getWindow } from './getters';\n\n/**\n * Returns the annotation object from the mirador slice.\n * @param {object} state redux state\n * @returns {object} Annotations from the state\n */\nexport const getAnnotations = (state) => miradorSlice(state).annotations;\n\nconst getMotivations = createSelector(\n [getConfig, (state, { motivations }) => motivations],\n (config, motivations) => motivations || config.annotations.filteredMotivations,\n);\n\nconst getAnnotationsOnCanvas = createSelector([getCanvas, getAnnotations], (canvas, annotations) => {\n if (!annotations || !canvas) return [];\n if (!annotations[canvas.id]) return [];\n\n return Object.values(annotations[canvas.id]).flat();\n});\n\nconst getPresentAnnotationsCanvas = createSelector([getAnnotationsOnCanvas], (annotations) =>\n filter(\n Object.values(annotations).map((annotation) => annotation && AnnotationFactory.determineAnnotation(annotation.json)),\n (annotation) => annotation && annotation.present(),\n ),\n);\n\nconst getAnnotationsOnSelectedCanvases = createSelector(\n [(state, { canvasId, ...otherProps }) => (canvasId ? [canvasId] : getVisibleCanvasIds(state, otherProps)), getAnnotations],\n (canvasIds, annotations) => {\n if (!annotations || canvasIds.length === 0) return [];\n return canvasIds.flatMap((targetId) => annotations[targetId] && Object.values(annotations[targetId]));\n },\n);\n\n/**\n * Returns an array of present annotations given a canvasId.\n * @param {object} state redux state\n * @param {string} canvasId canvasId\n * @returns {Array} An array of present annotations\n */\nexport const getPresentAnnotationsOnSelectedCanvases = createSelector([getAnnotationsOnSelectedCanvases], (annotations) =>\n filter(\n Object.values(annotations).map((annotation) => annotation && AnnotationFactory.determineAnnotation(annotation.json)),\n (annotation) => annotation && annotation.present(),\n ),\n);\n\n/**\n * Returns an array of annotation resources filtered by the given motivation for a particular canvas.\n * @param {Array} annotations\n * @param {Array} motivations\n * @returns {Array}\n */\nexport const getAnnotationResourcesByMotivationForCanvas = createSelector(\n [getPresentAnnotationsCanvas, getMotivations],\n (annotations, motivations) => {\n const resources = annotations.flatMap((annotation) => annotation.resources);\n\n // If motivations is empty, null, or undefined, return everything\n if (!motivations || motivations.length === 0) {\n return resources;\n }\n\n // Otherwise filter by motivations\n return resources.filter((resource) => resource.motivations.some((motivation) => motivations.includes(motivation)));\n },\n);\n\n/**\n * Returns annotation resources for a canvas destructured into their id/content/tags/targetId.\n * @param {object} state\n * @param {object} props\n * @param {string} props.canvasId\n * @param {string} props.windowId\n * @returns {Array} [{ id: 'abc123', content: 'Annotation Content' }, ...]\n */\nexport const getAnnotationResourcesDataForCanvas = createSelector([getAnnotationResourcesByMotivationForCanvas], (resources) =>\n resources.map((resource) => ({\n content: resource.chars,\n id: resource.id,\n tags: resource.tags,\n targetId: resource.targetId,\n })),\n);\n\n/**\n * Returns an array of annotation resources filtered by the given motivation.\n * @param {Array} annotations\n * @param {Array} motivations\n * @returns {Array}\n */\nexport const getAnnotationResourcesByMotivation = createSelector(\n [getPresentAnnotationsOnSelectedCanvases, getMotivations],\n (annotations, motivations) => {\n const resources = annotations.flatMap((annotation) => annotation.resources);\n\n // If motivations is empty, null, or undefined, return everything\n if (!motivations || motivations.length === 0) {\n return resources;\n }\n\n // Otherwise filter by motivations\n return resources.filter((resource) => resource.motivations.some((motivation) => motivations.includes(motivation)));\n },\n);\n\n/**\n * Returns the selected annotations IDs.\n * @param {object} state\n * @param {string} windowId\n * @param {Array} targetIds\n * @returns {Array}\n */\nexport const getSelectedAnnotationId = createSelector([getWindow], ({ selectedAnnotationId }) => selectedAnnotationId);\n\n/**\n * Returns annotations on selected canvases.\n * @param {object} state\n * @returns {Array}\n */\nexport const getSelectedAnnotationsOnCanvases = createSelector(\n [getPresentAnnotationsOnSelectedCanvases, getSelectedAnnotationId],\n (canvasAnnotations, selectedAnnotationId) =>\n canvasAnnotations\n .map((annotation) => ({\n id: annotation['@id'] || annotation.id,\n resources: annotation.resources.filter((r) => selectedAnnotationId === r.id),\n }))\n .filter((val) => val.resources.length > 0),\n);\n","import { createSelector } from 'reselect';\nimport { PropertyValue } from 'manifesto.js';\nimport AnnotationList from '../../lib/AnnotationList';\nimport { getCanvas, getCanvases } from './canvases';\nimport { getWindow } from './getters';\nimport { getManifestLocale } from './manifests';\nimport { miradorSlice, EMPTY_ARRAY, EMPTY_OBJECT } from './utils';\n\n/**\n * Get searches from state.\n */\nconst getSearches = (state) => miradorSlice(state).searches;\n\n/**\n * Returns the search result for a specific window.\n * @param {object} state\n * @param {string} windowId\n * @returns {object}\n */\nexport const getSearchForWindow = createSelector([(state, { windowId }) => windowId, getSearches], (windowId, searches) => {\n if (!windowId || !searches) return EMPTY_OBJECT;\n\n return searches[windowId];\n});\n\n/**\n * Returns the search result for a specific companion window.\n * @param {object} state\n * @param {string} companionWindowId\n * @returns {object|undefined}\n */\nconst getSearchForCompanionWindow = createSelector(\n [getSearchForWindow, (state, { companionWindowId }) => companionWindowId],\n (results, companionWindowId) => {\n if (!results || !companionWindowId) return undefined;\n return results[companionWindowId];\n },\n);\n\n/**\n * Returns an array of search responses for a specific companion window.\n * @param {object} state\n * @returns {Array}\n */\nconst getSearchResponsesForCompanionWindow = createSelector([getSearchForCompanionWindow], (results) => {\n if (!results) return EMPTY_ARRAY;\n return Object.values(results.data);\n});\n\n/**\n * Returns the search query for a specific companion window.\n * @param {object} state\n * @param {string} windowId\n * @returns {string|undefined}\n */\nexport const getSearchQuery = createSelector([getSearchForCompanionWindow], (results) => results && results.query);\n\n/**\n * Returns if search response for a companion window is fetching.\n * @param {object} state\n * @returns {boolean}\n */\nexport const getSearchIsFetching = createSelector([getSearchResponsesForCompanionWindow], (results) =>\n results.some((result) => result.isFetching),\n);\n\n/**\n * Returns the total number of search results for a companion window.\n * @param {object} state\n * @param {string} windowId\n * @returns {number|undefined}\n */\nexport const getSearchNumTotal = createSelector([getSearchForCompanionWindow], (results) => {\n if (!results || !results.data) return undefined;\n\n const resultWithWithin = Object.values(results.data).find((result) => !result.isFetching && result.json && result.json.within);\n return resultWithWithin?.json?.within?.total;\n});\n\n/**\n * Returns the Id of the next search.\n * @param {object} state\n * @param {string} windowId\n * @returns {number|undefined}\n */\nexport const getNextSearchId = createSelector([getSearchForCompanionWindow], (results) => {\n if (!results || !results.data) return undefined;\n\n const resultWithAnUnresolvedNext = Object.values(results.data).find(\n (result) => !result.isFetching && result.json && result.json.next && !results.data[result.json.next],\n );\n\n return resultWithAnUnresolvedNext && resultWithAnUnresolvedNext.json && resultWithAnUnresolvedNext.json.next;\n});\n\nconst getSearchHitsForCompanionWindow = createSelector([getSearchResponsesForCompanionWindow], (results) =>\n results.flatMap((result) => {\n if (!result || !result.json || result.isFetching || !result.json.hits) return EMPTY_ARRAY;\n\n return result.json.hits;\n }),\n);\n\nexport const getSearchAnnotationsForCompanionWindow = createSelector(\n [getSearchResponsesForCompanionWindow],\n (results) => results && searchResultsToAnnotation(results),\n);\n\n/**\n * Returns sorted search hits based on canvas order.\n * @param {object} state\n * @param {string} manifestId\n * @returns {Array}\n */\nexport const getSortedSearchHitsForCompanionWindow = createSelector(\n [getSearchHitsForCompanionWindow, getCanvases, getSearchAnnotationsForCompanionWindow],\n (searchHits, canvases, annotation) => {\n if (!canvases || canvases.length === 0) return EMPTY_ARRAY;\n if (!searchHits || searchHits.length === 0) return EMPTY_ARRAY;\n const canvasIds = canvases.map((canvas) => canvas.id);\n\n return [].concat(searchHits).sort((a, b) => {\n const hitA = annotation.resources.find((r) => r.id === a.annotations[0]);\n const hitB = annotation.resources.find((r) => r.id === b.annotations[0]);\n return canvasIds.indexOf(hitA.targetId) - canvasIds.indexOf(hitB.targetId);\n });\n },\n);\n\n/** convert search results to an annotation */\nconst searchResultsToAnnotation = (results) => {\n const annotations = results\n .map((result) => {\n if (!result || !result.json || result.isFetching || !result.json.resources) return undefined;\n const anno = new AnnotationList(result.json);\n return {\n id: anno.id,\n resources: anno.resources,\n };\n })\n .filter(Boolean);\n\n return {\n id: (annotations.find((a) => a.id) || {}).id,\n resources: annotations.flatMap((a) => a.resources),\n };\n};\n\n/**\n * Sorts search annotations based on canvas order.\n * @returns {Array}\n */\nexport function sortSearchAnnotationsByCanvasOrder(searchAnnotations, canvases) {\n if (!searchAnnotations || !searchAnnotations.resources || searchAnnotations.length === 0) return EMPTY_ARRAY;\n if (!canvases || canvases.length === 0) return EMPTY_ARRAY;\n const canvasIds = canvases.map((canvas) => canvas.id);\n\n return []\n .concat(searchAnnotations.resources)\n .sort((annoA, annoB) => canvasIds.indexOf(annoA.targetId) - canvasIds.indexOf(annoB.targetId));\n}\n\n/**\n * Returns sorted search annotations for companion window.\n * @param {object} state\n * @param {string} companionWindowId\n * @returns {Array}\n */\nexport const getSortedSearchAnnotationsForCompanionWindow = createSelector(\n [getSearchAnnotationsForCompanionWindow, getCanvases],\n (searchAnnotations, canvases) => sortSearchAnnotationsByCanvasOrder(searchAnnotations, canvases),\n);\n\n/**\n * Returns sorted search annotations for window.\n * @param {object} state\n * @param {string} windowId\n * @returns {Array}\n */\nexport const getSearchAnnotationsForWindow = createSelector([getSearchForWindow], (results) => {\n if (!results) return EMPTY_ARRAY;\n const data = Object.values(results).map((r) => Object.values(r.data));\n\n return data.map((d) => searchResultsToAnnotation(d)).filter((a) => a.resources.length > 0);\n});\n\n/**\n * Returns ids of selected content search annotations.\n * @param {object} state\n * @param {string} windowId\n * @returns {Array}\n */\nexport const getSelectedContentSearchAnnotationIds = createSelector(\n [getWindow, getSearchForCompanionWindow],\n (window, search) => (search && search.selectedContentSearchAnnotationIds) || [],\n);\n\n/**\n * Returns resource annotations for search hit.\n * @param {object} state\n * @param {string} windowId\n * @returns {Array}\n */\nexport const getResourceAnnotationForSearchHit = createSelector(\n [getSearchAnnotationsForCompanionWindow, (state, { annotationUri }) => annotationUri],\n (annotation, annotationUri) => annotation.resources.find((r) => r.id === annotationUri),\n);\n\n/**\n * Returns annotation label.\n * @param {object} state\n * @param {string} windowId\n * @returns {Array}\n */\nexport const getResourceAnnotationLabel = createSelector(\n [getResourceAnnotationForSearchHit, getManifestLocale],\n (resourceAnnotation, locale) => {\n if (!(resourceAnnotation && resourceAnnotation.resource && resourceAnnotation.resource.label)) return EMPTY_ARRAY;\n\n return PropertyValue.parse(resourceAnnotation.resource.label).getValues(locale);\n },\n);\n\nconst getAnnotationById = createSelector(\n [getSearchAnnotationsForWindow, (state, { annotationId }) => annotationId],\n (annotations, annotationId) => {\n const resourceAnnotations = annotations.flatMap((a) => a.resources);\n return resourceAnnotations.find((r) => r.id === annotationId);\n },\n);\n\n/**\n * Returns annotation label.\n * @param {object} state\n * @param {string} windowId\n * @returns {Array}\n */\nexport const getCanvasForAnnotation = createSelector(\n [\n getAnnotationById,\n (state, { windowId }) =>\n (canvasId) =>\n getCanvas(state, { canvasId, windowId }),\n ],\n (annotation, getCanvasById) => {\n const canvasId = annotation && annotation.targetId;\n return canvasId && getCanvasById(canvasId);\n },\n);\n","import ActionTypes from './action-types';\n\n/**\n * Request annotations on a canvas\n *\n * NOTE: there is no corresponding reducer; the expected API is sagas will\n * pick this action up and act on it accordingly.\n */\nexport function requestCanvasAnnotations(windowId, canvasId) {\n return {\n canvasId,\n type: ActionTypes.REQUEST_CANVAS_ANNOTATIONS,\n windowId,\n };\n}\n\n/**\n * requestAnnotation - action creator\n *\n * @param {String} targetId\n * @param {String} annotationId\n * @memberof ActionCreators\n */\nexport function requestAnnotation(targetId, annotationId) {\n return {\n annotationId,\n targetId,\n type: ActionTypes.REQUEST_ANNOTATION,\n };\n}\n\n/**\n * receiveAnnotation - action creator\n *\n * @param {String} targetId\n * @param {String} annotationId\n * @param {Object} annotationJson\n * @memberof ActionCreators\n */\nexport function receiveAnnotation(targetId, annotationId, annotationJson) {\n return {\n annotationId,\n annotationJson,\n targetId,\n type: ActionTypes.RECEIVE_ANNOTATION,\n };\n}\n\n/**\n * receiveAnnotationFailure - action creator\n *\n * @param {String} targetId\n * @param {String} annotationId\n * @param {String} error\n * @memberof ActionCreators\n */\nexport function receiveAnnotationFailure(targetId, annotationId, error) {\n return {\n annotationId,\n error,\n targetId,\n type: ActionTypes.RECEIVE_ANNOTATION_FAILURE,\n };\n}\n\n/**\n * selectAnnotation - action creator\n *\n * @param {String} windowId\n * @param {String} targetId\n * @param {String} annotationId\n * @memberof ActionCreators\n */\nexport function selectAnnotation(windowId, annotationId) {\n return {\n annotationId,\n type: ActionTypes.SELECT_ANNOTATION,\n windowId,\n };\n}\n\n/**\n * deselectAnnotation - action creator\n *\n * @param {String} windowId\n * @param {String} targetId\n * @param {String} annotationId\n * @memberof ActionCreators\n */\nexport function deselectAnnotation(windowId, annotationId) {\n return {\n annotationId,\n type: ActionTypes.DESELECT_ANNOTATION,\n windowId,\n };\n}\n\n/**\n * toggleAnnotationDisplay - action creator\n *\n * @param {String} windowId\n * @memberof ActionCreators\n */\nexport function toggleAnnotationDisplay(windowId) {\n return {\n type: ActionTypes.TOGGLE_ANNOTATION_DISPLAY,\n windowId,\n };\n}\n\n/**\n * toggleAnnotationDisplay - action creator\n *\n * @param {String} windowId\n * @memberof ActionCreators\n */\nexport function hoverAnnotation(windowId, annotationIds) {\n return {\n annotationIds,\n type: ActionTypes.HOVER_ANNOTATION,\n windowId,\n };\n}\n","import { createContext } from 'react';\n\nconst FailedImageContext = createContext({\n fallbackImage: '',\n hasFailed: false,\n notifyFailure: () => {},\n});\nexport default FailedImageContext;\n"],"x_google_ignoreList":[0,1,2],"mappings":"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"}
|