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.
Files changed (42) hide show
  1. package/dist/{AudioViewer-tRH73pbt.js → AudioViewer-Cla9W2NI.js} +2 -2
  2. package/dist/{AudioViewer-tRH73pbt.js.map → AudioViewer-Cla9W2NI.js.map} +1 -1
  3. package/dist/{CommentSharp-BJ6oQAe3.js → CommentSharp-BB9dWNcO.js} +3 -3
  4. package/dist/{CommentSharp-BJ6oQAe3.js.map → CommentSharp-BB9dWNcO.js.map} +1 -1
  5. package/dist/{FailedImageContext-BhA0TpVp.js → FailedImageContext-C-8e4l3r.js} +14 -8
  6. package/dist/FailedImageContext-C-8e4l3r.js.map +1 -0
  7. package/dist/{GalleryView-rCx0Q4f3.js → GalleryView-BS7q2lC0.js} +5 -5
  8. package/dist/{GalleryView-rCx0Q4f3.js.map → GalleryView-BS7q2lC0.js.map} +1 -1
  9. package/dist/{OpenSeadragonViewer-4nw8qaVM.js → OpenSeadragonViewer-DtalKKE4.js} +312 -293
  10. package/dist/{OpenSeadragonViewer-4nw8qaVM.js.map → OpenSeadragonViewer-DtalKKE4.js.map} +1 -1
  11. package/dist/{TextViewer-D_1qzQE4.js → TextViewer-Dn04175s.js} +3 -3
  12. package/dist/{TextViewer-D_1qzQE4.js.map → TextViewer-Dn04175s.js.map} +1 -1
  13. package/dist/{VideoViewer-DzNjgLWE.js → VideoViewer-Db17A1Pj.js} +2 -2
  14. package/dist/{VideoViewer-DzNjgLWE.js.map → VideoViewer-Db17A1Pj.js.map} +1 -1
  15. package/dist/{WindowCanvasNavigationControls-D2uLtL_A.js → WindowCanvasNavigationControls-BEfgwEVZ.js} +3 -3
  16. package/dist/{WindowCanvasNavigationControls-D2uLtL_A.js.map → WindowCanvasNavigationControls-BEfgwEVZ.js.map} +1 -1
  17. package/dist/{WindowViewer-uHVYcMsX.js → WindowViewer-Bwx-8xYM.js} +3 -3
  18. package/dist/{WindowViewer-uHVYcMsX.js.map → WindowViewer-Bwx-8xYM.js.map} +1 -1
  19. package/dist/{WorkspaceArea-7bydz9m-.js → WorkspaceArea-SpTGn3q2.js} +4019 -3998
  20. package/dist/WorkspaceArea-SpTGn3q2.js.map +1 -0
  21. package/dist/{canvas-2ACcnS9Y.js → canvas-CnyCCdkT.js} +2 -2
  22. package/dist/{canvas-2ACcnS9Y.js.map → canvas-CnyCCdkT.js.map} +1 -1
  23. package/dist/{canvases-DTR37lo-.js → canvases-Bxeg1axY.js} +255 -255
  24. package/dist/{canvases-DTR37lo-.js.map → canvases-Bxeg1axY.js.map} +1 -1
  25. package/dist/{index.module-CgUBfaXx.js → index.module-BYoozchK.js} +7 -7
  26. package/dist/{index.module-CgUBfaXx.js.map → index.module-BYoozchK.js.map} +1 -1
  27. package/dist/mirador.es.js +1593 -1446
  28. package/dist/mirador.es.js.map +1 -1
  29. package/dist/mirador.min.js +30 -27
  30. package/dist/mirador.min.js.map +1 -1
  31. package/package.json +1 -1
  32. package/src/components/AnnotationsOverlay.jsx +28 -1
  33. package/src/components/CompanionWindow.jsx +39 -2
  34. package/src/components/MapViewer.jsx +77 -4
  35. package/src/lib/AnnotationItem.js +5 -0
  36. package/src/lib/AnnotationResource.js +5 -0
  37. package/src/lib/CanvasAnnotationDisplay.js +52 -14
  38. package/src/plugins/index.js +1 -0
  39. package/src/plugins/nestedMapPlugin.tsx +152 -0
  40. package/src/plugins/poiPreviewPlugin.tsx +256 -77
  41. package/dist/FailedImageContext-BhA0TpVp.js.map +0 -1
  42. package/dist/WorkspaceArea-7bydz9m-.js.map +0 -1
@@ -1,19 +1,28 @@
1
- import { useState, type ComponentType } from 'react';
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: instead of the "dumb" dual-locale dump
28
- // below, a Journey renders its ordered stops as numbered cards with a single active
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
- // Both locales, side by side - see the module comment above: the point of a "dumb" preview
68
- // is to see everything a poi/journey holds, not to render it the way the public site
69
- // eventually will for one active language.
70
- const LOCALES = ['en', 'ar'] as const;
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: (typeof LOCALES)[number]): DbfMedia | null | undefined =>
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
- const JOURNEY_PREVIEW_LOCALES = ['en', 'ar'] as const;
96
- type JourneyPreviewLocale = (typeof JOURNEY_PREVIEW_LOCALES)[number];
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
- // Arabic is the only RTL locale this project handles today (mirrors the same check in
99
- // mirador-annotation-editor's POITemplate.jsx/JourneyTemplate.jsx).
100
- const isRtlLocale = (locale: string) => locale.toLowerCase().startsWith('ar');
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 = ({ id, journey, pois, windowId }: JourneyPreviewContentProps) => {
110
- const [locale, setLocale] = useState<JourneyPreviewLocale>('en');
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 || 'Journey'} windowId={windowId}>
115
- <div dir={isRtlLocale(locale) ? 'rtl' : 'ltr'} style={{ padding: 16 }}>
116
- <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 4, marginBottom: 16 }}>
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 key={poi.id} style={{ display: 'flex' }}>
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 = ({ annotation, id, windowId }: PoiPreviewContentProps) => (
201
- <CompanionWindow id={id} title={annotation?.['dbf:kind'] ?? 'Preview'} windowId={windowId}>
202
- <div style={{ padding: 16 }}>
203
- {!annotation && <p>This annotation could not be found - it may have been deleted.</p>}
204
- {annotation &&
205
- LOCALES.map((locale) => {
206
- const title = textBody(annotation, locale, 'identifying');
207
- const description = textBody(annotation, locale, 'describing');
208
- const media = mediaForLocale(annotation, locale);
209
- return (
210
- <section key={locale} style={{ marginBottom: 24 }}>
211
- <h3 style={{ textTransform: 'uppercase' }}>{locale}</h3>
212
- <p>
213
- <strong>{title || '—'}</strong>
214
- </p>
215
- {description && (
216
- // eslint-disable-next-line react/no-danger -- descriptionEn/Ar is CKEditor HTML, the same content the public site will eventually render
217
- <div dangerouslySetInnerHTML={{ __html: description }} />
218
- )}
219
- {media &&
220
- (media.thumbnailUrl ? (
221
- <img alt={media.title ?? ''} src={media.thumbnailUrl} style={{ maxWidth: '100%' }} />
222
- ) : (
223
- <p>
224
- {media.title}
225
- {media.mediaType ? ` (${media.mediaType})` : ''}
226
- </p>
227
- ))}
228
- </section>
229
- );
230
- })}
231
- </div>
232
- </CompanionWindow>
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 = ({ annotation, id, journeyPois, windowId }: PreviewContentProps) => {
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 <JourneyPreviewContent id={id} journey={annotation} pois={journeyPois} windowId={windowId} />;
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 <PoiPreviewContent annotation={annotation} id={id} windowId={windowId} />;
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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"}