dbf-mirador 4.2.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/LICENSE +203 -0
- package/README.md +133 -0
- package/dist/CommentSharp-B0J_-jEq.js +325 -0
- package/dist/CommentSharp-B0J_-jEq.js.map +1 -0
- package/dist/FailedImageContext-aQXnWSHN.js +318 -0
- package/dist/FailedImageContext-aQXnWSHN.js.map +1 -0
- package/dist/PluginHook-CFw_6P5c.js +54 -0
- package/dist/PluginHook-CFw_6P5c.js.map +1 -0
- package/dist/WindowCanvasNavigationControls-CUX723BQ.js +242 -0
- package/dist/WindowCanvasNavigationControls-CUX723BQ.js.map +1 -0
- package/dist/action-types-DjIbTE-A.js +74 -0
- package/dist/action-types-DjIbTE-A.js.map +1 -0
- package/dist/canvas-C8oHvXFN.js +41 -0
- package/dist/canvas-C8oHvXFN.js.map +1 -0
- package/dist/canvases-gRqhr-IH.js +3154 -0
- package/dist/canvases-gRqhr-IH.js.map +1 -0
- package/dist/createSvgIcon-Cwt8YPfm.js +2 -0
- package/dist/getters-COus7Mvg.js +2066 -0
- package/dist/getters-COus7Mvg.js.map +1 -0
- package/dist/index.module-CbBRf_R8.js +403 -0
- package/dist/index.module-CbBRf_R8.js.map +1 -0
- package/dist/mirador.es.js +39600 -0
- package/dist/mirador.es.js.map +1 -0
- package/dist/mirador.min.js +334 -0
- package/dist/mirador.min.js.map +1 -0
- package/dist/react-error-boundary.esm-B_pT-oCS.js +67 -0
- package/dist/react-error-boundary.esm-B_pT-oCS.js.map +1 -0
- package/dist/visuallyHidden-DmYvwNdU.js +98 -0
- package/dist/visuallyHidden-DmYvwNdU.js.map +1 -0
- package/dist/window-zelwU7wz.js +138 -0
- package/dist/window-zelwU7wz.js.map +1 -0
- package/package.json +138 -0
- package/src/components/AccessTokenSender.jsx +34 -0
- package/src/components/AnnotationSettings.jsx +31 -0
- package/src/components/AnnotationsOverlay.jsx +328 -0
- package/src/components/App.jsx +34 -0
- package/src/components/AppProviders.jsx +129 -0
- package/src/components/AttributionPanel.jsx +78 -0
- package/src/components/AudioViewer.jsx +39 -0
- package/src/components/BackgroundPluginArea.jsx +9 -0
- package/src/components/Branding.jsx +33 -0
- package/src/components/CanvasAnnotations.jsx +125 -0
- package/src/components/CanvasInfo.jsx +46 -0
- package/src/components/CanvasLayers.jsx +367 -0
- package/src/components/ChangeThemeDialog.jsx +65 -0
- package/src/components/CollapsibleSection.jsx +53 -0
- package/src/components/CollectionDialog.jsx +236 -0
- package/src/components/CollectionInfo.jsx +48 -0
- package/src/components/CompanionArea.jsx +140 -0
- package/src/components/CompanionWindow.jsx +228 -0
- package/src/components/CompanionWindowFactory.jsx +38 -0
- package/src/components/CompanionWindowSection.jsx +11 -0
- package/src/components/CustomPanel.jsx +22 -0
- package/src/components/ErrorContent.jsx +65 -0
- package/src/components/ErrorDialog.jsx +47 -0
- package/src/components/FullScreenButton.jsx +47 -0
- package/src/components/GalleryView.jsx +36 -0
- package/src/components/GalleryViewThumbnail.jsx +160 -0
- package/src/components/IIIFAuthentication.jsx +144 -0
- package/src/components/IIIFDropTarget.jsx +168 -0
- package/src/components/IIIFIFrameCommunication.jsx +45 -0
- package/src/components/IIIFResourceLabel.jsx +26 -0
- package/src/components/IIIFThumbnail.jsx +214 -0
- package/src/components/ImageFailureMessage.jsx +42 -0
- package/src/components/LabelValueMetadata.jsx +46 -0
- package/src/components/LanguageSettings.jsx +46 -0
- package/src/components/LayersPanel.jsx +24 -0
- package/src/components/LocalePicker.jsx +56 -0
- package/src/components/ManifestForm.jsx +79 -0
- package/src/components/ManifestInfo.jsx +67 -0
- package/src/components/ManifestListItem.jsx +209 -0
- package/src/components/ManifestListItemError.jsx +53 -0
- package/src/components/ManifestRelatedLinks.jsx +154 -0
- package/src/components/MinimalWindow.jsx +104 -0
- package/src/components/MiradorMenuButton.jsx +71 -0
- package/src/components/MosaicRenderPreview.jsx +16 -0
- package/src/components/NestedMenu.jsx +42 -0
- package/src/components/NewBrowserWindow.jsx +34 -0
- package/src/components/OpenSeadragonComponent.jsx +258 -0
- package/src/components/OpenSeadragonTileSource.jsx +105 -0
- package/src/components/OpenSeadragonViewer.jsx +161 -0
- package/src/components/PluginHook.jsx +27 -0
- package/src/components/PrimaryWindow.jsx +115 -0
- package/src/components/SanitizedHtml.jsx +37 -0
- package/src/components/ScrollIndicatedDialogContent.jsx +60 -0
- package/src/components/ScrollTo.jsx +61 -0
- package/src/components/SearchHit.jsx +220 -0
- package/src/components/SearchPanel.jsx +80 -0
- package/src/components/SearchPanelControls.jsx +174 -0
- package/src/components/SearchPanelNavigation.jsx +84 -0
- package/src/components/SearchResults.jsx +138 -0
- package/src/components/SelectCollection.jsx +44 -0
- package/src/components/SidebarIndexItem.jsx +11 -0
- package/src/components/SidebarIndexList.jsx +73 -0
- package/src/components/SidebarIndexTableOfContents.jsx +170 -0
- package/src/components/SidebarIndexThumbnail.jsx +22 -0
- package/src/components/TextViewer.jsx +37 -0
- package/src/components/ThumbnailCanvasGrouping.jsx +122 -0
- package/src/components/ThumbnailNavigation.jsx +231 -0
- package/src/components/VideoViewer.jsx +35 -0
- package/src/components/ViewerInfo.jsx +55 -0
- package/src/components/ViewerNavigation.jsx +72 -0
- package/src/components/Window.jsx +150 -0
- package/src/components/WindowAuthenticationBar.jsx +176 -0
- package/src/components/WindowCanvasNavigationControls.jsx +91 -0
- package/src/components/WindowList.jsx +71 -0
- package/src/components/WindowListButton.jsx +57 -0
- package/src/components/WindowSideBar.jsx +48 -0
- package/src/components/WindowSideBarAnnotationsPanel.jsx +51 -0
- package/src/components/WindowSideBarButtons.jsx +151 -0
- package/src/components/WindowSideBarCanvasPanel.jsx +165 -0
- package/src/components/WindowSideBarCollectionPanel.jsx +179 -0
- package/src/components/WindowSideBarInfoPanel.jsx +67 -0
- package/src/components/WindowThumbnailSettings.jsx +130 -0
- package/src/components/WindowTopBar.jsx +125 -0
- package/src/components/WindowTopBarPluginArea.jsx +8 -0
- package/src/components/WindowTopBarPluginMenu.jsx +78 -0
- package/src/components/WindowTopBarTitle.jsx +73 -0
- package/src/components/WindowTopMenu.jsx +81 -0
- package/src/components/WindowTopMenuButton.jsx +49 -0
- package/src/components/WindowViewSettings.jsx +95 -0
- package/src/components/WindowViewer.jsx +26 -0
- package/src/components/Workspace.jsx +124 -0
- package/src/components/WorkspaceAdd.jsx +221 -0
- package/src/components/WorkspaceAddButton.jsx +73 -0
- package/src/components/WorkspaceArea.jsx +66 -0
- package/src/components/WorkspaceControlPanel.jsx +85 -0
- package/src/components/WorkspaceControlPanelButtons.jsx +20 -0
- package/src/components/WorkspaceDialog.jsx +11 -0
- package/src/components/WorkspaceElastic.jsx +88 -0
- package/src/components/WorkspaceElasticWindow.jsx +79 -0
- package/src/components/WorkspaceExport.jsx +99 -0
- package/src/components/WorkspaceImport.jsx +89 -0
- package/src/components/WorkspaceMenu.jsx +126 -0
- package/src/components/WorkspaceMenuButton.jsx +42 -0
- package/src/components/WorkspaceMosaic.jsx +149 -0
- package/src/components/WorkspaceOptionsButton.jsx +35 -0
- package/src/components/WorkspaceOptionsMenu.jsx +112 -0
- package/src/components/WorkspaceSelectionDialog.jsx +165 -0
- package/src/components/ZoomControls.jsx +57 -0
- package/src/components/icons/BookViewIcon.jsx +14 -0
- package/src/components/icons/CanvasIndexIcon.jsx +14 -0
- package/src/components/icons/GalleryViewIcon.jsx +17 -0
- package/src/components/icons/MiradorIcon.jsx +14 -0
- package/src/components/icons/RestoreZoomIcon.jsx +15 -0
- package/src/components/icons/ThumbnailNavigationBottomIcon.jsx +15 -0
- package/src/components/icons/ThumbnailNavigationRightIcon.jsx +16 -0
- package/src/components/icons/WindowMaxIcon.jsx +15 -0
- package/src/components/icons/WindowMinIcon.jsx +15 -0
- package/src/components/icons/WindowOptionsIcon.jsx +16 -0
- package/src/components/icons/WorkspaceTypeElasticIcon.jsx +157 -0
- package/src/components/icons/WorkspaceTypeMosaicIcon.jsx +162 -0
- package/src/components/icons/index.js +27 -0
- package/src/components/index.js +108 -0
- package/src/config/css-ns.js +10 -0
- package/src/config/index.js +2 -0
- package/src/config/settings.js +607 -0
- package/src/containers/AnnotationSettings.js +27 -0
- package/src/containers/AnnotationsOverlay.js +51 -0
- package/src/containers/AppProviders.js +20 -0
- package/src/containers/AttributionPanel.js +20 -0
- package/src/containers/AudioViewer.js +16 -0
- package/src/containers/BackgroundPluginArea.js +4 -0
- package/src/containers/Branding.js +4 -0
- package/src/containers/CanvasAnnotations.js +32 -0
- package/src/containers/CanvasInfo.js +20 -0
- package/src/containers/CanvasLayers.js +25 -0
- package/src/containers/ChangeThemeDialog.js +29 -0
- package/src/containers/CollapsibleSection.js +3 -0
- package/src/containers/CollectionDialog.js +48 -0
- package/src/containers/CollectionInfo.js +29 -0
- package/src/containers/CompanionArea.js +22 -0
- package/src/containers/CompanionWindow.js +40 -0
- package/src/containers/CompanionWindowFactory.js +23 -0
- package/src/containers/CustomPanel.js +13 -0
- package/src/containers/ErrorContent.js +20 -0
- package/src/containers/ErrorDialog.js +28 -0
- package/src/containers/FullScreenButton.js +22 -0
- package/src/containers/GalleryView.js +23 -0
- package/src/containers/GalleryViewThumbnail.js +51 -0
- package/src/containers/IIIFAuthentication.js +86 -0
- package/src/containers/IIIFThumbnail.js +17 -0
- package/src/containers/LabelValueMetadata.js +14 -0
- package/src/containers/LanguageSettings.js +26 -0
- package/src/containers/LayersPanel.js +16 -0
- package/src/containers/LocalePicker.js +3 -0
- package/src/containers/ManifestForm.js +16 -0
- package/src/containers/ManifestInfo.js +29 -0
- package/src/containers/ManifestListItem.js +52 -0
- package/src/containers/ManifestListItemError.js +15 -0
- package/src/containers/ManifestRelatedLinks.js +28 -0
- package/src/containers/MinimalWindow.js +25 -0
- package/src/containers/MiradorMenuButton.js +7 -0
- package/src/containers/MosaicRenderPreview.js +14 -0
- package/src/containers/OpenSeadragonViewer.js +59 -0
- package/src/containers/PrimaryWindow.js +27 -0
- package/src/containers/SanitizedHtml.js +3 -0
- package/src/containers/ScrollIndicatedDialogContent.js +3 -0
- package/src/containers/SearchHit.js +71 -0
- package/src/containers/SearchPanel.js +23 -0
- package/src/containers/SearchPanelControls.js +36 -0
- package/src/containers/SearchPanelNavigation.js +39 -0
- package/src/containers/SearchResults.js +38 -0
- package/src/containers/SelectCollection.js +24 -0
- package/src/containers/SidebarIndexItem.js +8 -0
- package/src/containers/SidebarIndexList.js +28 -0
- package/src/containers/SidebarIndexTableOfContents.js +31 -0
- package/src/containers/SidebarIndexThumbnail.js +18 -0
- package/src/containers/TextViewer.js +19 -0
- package/src/containers/ThumbnailCanvasGrouping.js +29 -0
- package/src/containers/ThumbnailNavigation.js +48 -0
- package/src/containers/VideoViewer.js +16 -0
- package/src/containers/ViewerInfo.js +30 -0
- package/src/containers/ViewerNavigation.js +31 -0
- package/src/containers/Window.js +45 -0
- package/src/containers/WindowAuthenticationBar.js +7 -0
- package/src/containers/WindowCanvasNavigationControls.js +15 -0
- package/src/containers/WindowList.js +30 -0
- package/src/containers/WindowListButton.js +15 -0
- package/src/containers/WindowSideBar.js +20 -0
- package/src/containers/WindowSideBarAnnotationsPanel.js +23 -0
- package/src/containers/WindowSideBarButtons.js +75 -0
- package/src/containers/WindowSideBarCanvasPanel.js +50 -0
- package/src/containers/WindowSideBarCollectionPanel.js +48 -0
- package/src/containers/WindowSideBarInfoPanel.js +35 -0
- package/src/containers/WindowThumbnailSettings.js +31 -0
- package/src/containers/WindowTopBar.js +39 -0
- package/src/containers/WindowTopBarPluginArea.js +8 -0
- package/src/containers/WindowTopBarPluginMenu.js +7 -0
- package/src/containers/WindowTopBarTitle.js +17 -0
- package/src/containers/WindowTopMenu.js +28 -0
- package/src/containers/WindowTopMenuButton.js +7 -0
- package/src/containers/WindowViewSettings.js +30 -0
- package/src/containers/WindowViewer.js +10 -0
- package/src/containers/Workspace.js +36 -0
- package/src/containers/WorkspaceAdd.js +27 -0
- package/src/containers/WorkspaceAddButton.js +30 -0
- package/src/containers/WorkspaceArea.js +21 -0
- package/src/containers/WorkspaceControlPanel.js +10 -0
- package/src/containers/WorkspaceControlPanelButtons.js +7 -0
- package/src/containers/WorkspaceElastic.js +41 -0
- package/src/containers/WorkspaceElasticWindow.js +36 -0
- package/src/containers/WorkspaceExport.js +18 -0
- package/src/containers/WorkspaceImport.js +19 -0
- package/src/containers/WorkspaceMenu.js +30 -0
- package/src/containers/WorkspaceMenuButton.js +10 -0
- package/src/containers/WorkspaceMosaic.js +32 -0
- package/src/containers/WorkspaceOptionsButton.js +7 -0
- package/src/containers/WorkspaceOptionsMenu.js +3 -0
- package/src/containers/WorkspaceSelectionDialog.js +26 -0
- package/src/containers/ZoomControls.js +26 -0
- package/src/containers/index.js +94 -0
- package/src/contexts/FailedImageContext.js +8 -0
- package/src/contexts/FailedImageProvider.jsx +34 -0
- package/src/contexts/FullScreenContext.js +5 -0
- package/src/contexts/LocaleContext.js +5 -0
- package/src/contexts/OpenSeadragonViewerContext.js +5 -0
- package/src/contexts/WorkspaceContext.js +5 -0
- package/src/contexts/index.js +4 -0
- package/src/extend/PluginContext.js +5 -0
- package/src/extend/PluginProvider.jsx +22 -0
- package/src/extend/index.js +9 -0
- package/src/extend/pluginMapping.js +44 -0
- package/src/extend/pluginPreprocessing.js +45 -0
- package/src/extend/pluginValidation.js +58 -0
- package/src/extend/usePlugins.js +13 -0
- package/src/extend/withPlugins.jsx +46 -0
- package/src/hooks/index.js +4 -0
- package/src/hooks/useCanvasWorldService.js +10 -0
- package/src/hooks/useThumbnailService.js +8 -0
- package/src/i18n.js +71 -0
- package/src/index.js +18 -0
- package/src/init.js +20 -0
- package/src/lib/AnnotationFactory.js +23 -0
- package/src/lib/AnnotationItem.js +123 -0
- package/src/lib/AnnotationList.js +31 -0
- package/src/lib/AnnotationPage.js +41 -0
- package/src/lib/AnnotationResource.js +122 -0
- package/src/lib/CanvasAnnotationDisplay.js +148 -0
- package/src/lib/CanvasGroupings.js +55 -0
- package/src/lib/CanvasWorld.js +214 -0
- package/src/lib/CompanionWindowRegistry.js +23 -0
- package/src/lib/FullScreenHandle.jsx +76 -0
- package/src/lib/MiradorCanvas.js +211 -0
- package/src/lib/MiradorManifest.js +44 -0
- package/src/lib/MiradorViewer.jsx +53 -0
- package/src/lib/MosaicLayout.js +77 -0
- package/src/lib/OpenSeadragonCanvasOverlay.js +114 -0
- package/src/lib/ThumbnailFactory.js +310 -0
- package/src/lib/TruncatedHit.js +34 -0
- package/src/lib/asArray.js +11 -0
- package/src/lib/htmlRules.js +28 -0
- package/src/lib/iiif.js +12 -0
- package/src/lib/index.js +23 -0
- package/src/lib/readImageMetadata.js +21 -0
- package/src/lib/svgShapesToPath.js +49 -0
- package/src/locales/README.md +60 -0
- package/src/locales/ar/translation.json +141 -0
- package/src/locales/bg/translation.json +164 -0
- package/src/locales/de/translation.json +169 -0
- package/src/locales/en/translation.json +170 -0
- package/src/locales/et/translation.json +164 -0
- package/src/locales/fa/translation.json +164 -0
- package/src/locales/fr/translation.json +158 -0
- package/src/locales/hr/translation.json +164 -0
- package/src/locales/hu/translation.json +166 -0
- package/src/locales/it/translation.json +162 -0
- package/src/locales/ja/translation.json +156 -0
- package/src/locales/kr/translation.json +162 -0
- package/src/locales/lt/translation.json +153 -0
- package/src/locales/nbNo/translation.json +162 -0
- package/src/locales/nl/translation.json +139 -0
- package/src/locales/pl/translation.json +162 -0
- package/src/locales/ptBr/translation.json +133 -0
- package/src/locales/sr/translation.json +155 -0
- package/src/locales/sv/translation.json +157 -0
- package/src/locales/ta/translation.json +167 -0
- package/src/locales/vi/translation.json +156 -0
- package/src/locales/zhCn/translation.json +163 -0
- package/src/locales/zhTw/translation.json +163 -0
- package/src/plugins/OSDReferences.js +15 -0
- package/src/plugins/index.js +1 -0
- package/src/state/actions/action-types.js +76 -0
- package/src/state/actions/annotation.js +123 -0
- package/src/state/actions/auth.js +109 -0
- package/src/state/actions/canvas.js +65 -0
- package/src/state/actions/catalog.js +22 -0
- package/src/state/actions/companionWindow.js +107 -0
- package/src/state/actions/config.js +49 -0
- package/src/state/actions/elasticLayout.js +10 -0
- package/src/state/actions/errors.js +22 -0
- package/src/state/actions/index.js +19 -0
- package/src/state/actions/infoResponse.js +90 -0
- package/src/state/actions/layers.js +14 -0
- package/src/state/actions/manifest.js +65 -0
- package/src/state/actions/search.js +97 -0
- package/src/state/actions/window.js +209 -0
- package/src/state/actions/workspace.js +84 -0
- package/src/state/createPluggableStore.js +24 -0
- package/src/state/createStore.js +33 -0
- package/src/state/index.js +21 -0
- package/src/state/reducers/accessTokens.js +59 -0
- package/src/state/reducers/annotations.js +48 -0
- package/src/state/reducers/auth.js +43 -0
- package/src/state/reducers/catalog.js +30 -0
- package/src/state/reducers/companionWindows.js +49 -0
- package/src/state/reducers/config.js +39 -0
- package/src/state/reducers/elasticLayout.js +29 -0
- package/src/state/reducers/errors.js +51 -0
- package/src/state/reducers/index.js +15 -0
- package/src/state/reducers/infoResponses.js +61 -0
- package/src/state/reducers/layers.js +23 -0
- package/src/state/reducers/manifests.js +52 -0
- package/src/state/reducers/rootReducer.js +44 -0
- package/src/state/reducers/search.js +145 -0
- package/src/state/reducers/utils.js +45 -0
- package/src/state/reducers/viewers.js +42 -0
- package/src/state/reducers/windows.js +185 -0
- package/src/state/reducers/workspace.js +111 -0
- package/src/state/sagas/annotations.js +48 -0
- package/src/state/sagas/app.js +56 -0
- package/src/state/sagas/auth.js +151 -0
- package/src/state/sagas/iiif.js +233 -0
- package/src/state/sagas/index.js +30 -0
- package/src/state/sagas/windows.js +293 -0
- package/src/state/selectors/annotations.js +138 -0
- package/src/state/selectors/auth.js +100 -0
- package/src/state/selectors/canvases.js +260 -0
- package/src/state/selectors/companionWindows.js +182 -0
- package/src/state/selectors/config.js +100 -0
- package/src/state/selectors/getters.js +90 -0
- package/src/state/selectors/index.js +17 -0
- package/src/state/selectors/layers.js +79 -0
- package/src/state/selectors/manifests.js +433 -0
- package/src/state/selectors/ranges.js +147 -0
- package/src/state/selectors/searches.js +249 -0
- package/src/state/selectors/sequences.js +134 -0
- package/src/state/selectors/thumbnails.js +28 -0
- package/src/state/selectors/utils.js +18 -0
- package/src/state/selectors/viewer.js +19 -0
- package/src/state/selectors/windows.js +98 -0
- package/src/state/selectors/workspace.js +52 -0
- package/src/state/selectors/wrappers.js +15 -0
- package/src/styles/react-mosaic-component.js +288 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { all, call, put, select, takeEvery } from 'redux-saga/effects';
|
|
2
|
+
import { Utils } from 'manifesto.js';
|
|
3
|
+
import normalizeUrl from 'normalize-url';
|
|
4
|
+
import ActionTypes from '../actions/action-types';
|
|
5
|
+
import {
|
|
6
|
+
receiveManifest,
|
|
7
|
+
receiveManifestFailure,
|
|
8
|
+
receiveInfoResponse,
|
|
9
|
+
receiveInfoResponseFailure,
|
|
10
|
+
receiveDegradedInfoResponse,
|
|
11
|
+
receiveSearch,
|
|
12
|
+
receiveSearchFailure,
|
|
13
|
+
receiveAnnotation,
|
|
14
|
+
receiveAnnotationFailure,
|
|
15
|
+
} from '../actions';
|
|
16
|
+
import { getManifests, getRequestsConfig, getAccessTokens, selectInfoResponse } from '../selectors';
|
|
17
|
+
|
|
18
|
+
/** */
|
|
19
|
+
function fetchWrapper(url, options, { success, degraded, failure }) {
|
|
20
|
+
return fetch(url, options)
|
|
21
|
+
.then((response) =>
|
|
22
|
+
response
|
|
23
|
+
.json()
|
|
24
|
+
.then((json) => {
|
|
25
|
+
if (response.status === 401) return (degraded || success)({ json, response });
|
|
26
|
+
if (response.ok) return success({ json, response });
|
|
27
|
+
return failure({ error: response.statusText, json, response });
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
// Error responses (4xx/5xx) often have a body that isn't valid JSON
|
|
31
|
+
// only surface the raw parse error when the response was otherwise ok,
|
|
32
|
+
// where it points to an actual unexpected JSON body bug.
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
return failure({ error: `${response.status} ${response.statusText}: ${url}`, response });
|
|
35
|
+
}
|
|
36
|
+
return failure({ error, response });
|
|
37
|
+
}),
|
|
38
|
+
)
|
|
39
|
+
.catch((error) => failure({ error }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** */
|
|
43
|
+
function* fetchIiifResource(url, options, { success, degraded, failure }) {
|
|
44
|
+
const { preprocessors = [], postprocessors = [] } = yield select(getRequestsConfig);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const reqOptions = preprocessors.reduce((acc, f) => f(url, acc) || acc, options);
|
|
48
|
+
|
|
49
|
+
let action = yield call(fetchWrapper, url, reqOptions, { degraded, failure, success });
|
|
50
|
+
action = postprocessors.reduce((acc, f) => f(url, acc) || acc, action);
|
|
51
|
+
return action;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
return failure({ error });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** */
|
|
58
|
+
function* fetchIiifResourceWithAuth(url, iiifResource, options, { degraded, failure, success }) {
|
|
59
|
+
const urlOptions = { ...options };
|
|
60
|
+
let tokenServiceId;
|
|
61
|
+
|
|
62
|
+
// If we have a requested IIIF resource (say, the image description from the manifest)
|
|
63
|
+
// we can optimistically try an appropriate access token.
|
|
64
|
+
//
|
|
65
|
+
// TODO: there might be multiple applicable access token services
|
|
66
|
+
if (iiifResource) {
|
|
67
|
+
const tokenService = yield call(getAccessTokenService, iiifResource);
|
|
68
|
+
tokenServiceId = tokenService && tokenService.id;
|
|
69
|
+
|
|
70
|
+
if (tokenService && tokenService.json) {
|
|
71
|
+
urlOptions.headers = {
|
|
72
|
+
Authorization: `Bearer ${tokenService.json.accessToken}`,
|
|
73
|
+
...options.headers,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const { error, json, response } = yield call(fetchIiifResource, url, urlOptions, {
|
|
79
|
+
failure: (arg) => arg,
|
|
80
|
+
success: (arg) => arg,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Hard error either requesting the resource or deserializing the JSON.
|
|
84
|
+
if (error) {
|
|
85
|
+
yield put(
|
|
86
|
+
failure({
|
|
87
|
+
error,
|
|
88
|
+
json,
|
|
89
|
+
response,
|
|
90
|
+
tokenServiceId,
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const id = json['@id'] || json.id;
|
|
97
|
+
if (response.ok) {
|
|
98
|
+
if (
|
|
99
|
+
normalizeUrl(id, { stripAuthentication: false }) ===
|
|
100
|
+
normalizeUrl(url.replace(/info\.json$/, ''), { stripAuthentication: false })
|
|
101
|
+
) {
|
|
102
|
+
yield put(success({ json, response, tokenServiceId }));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
} else if (response.status !== 401) {
|
|
106
|
+
yield put(
|
|
107
|
+
failure({
|
|
108
|
+
error,
|
|
109
|
+
json,
|
|
110
|
+
response,
|
|
111
|
+
tokenServiceId,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Start attempting some IIIF Auth;
|
|
119
|
+
// First, the IIIF resource we were given may not be authoritative; check if
|
|
120
|
+
// it suggests a different access token service and re-enter the auth workflow
|
|
121
|
+
const authoritativeTokenService = yield call(getAccessTokenService, json);
|
|
122
|
+
if (authoritativeTokenService && authoritativeTokenService.id !== tokenServiceId) {
|
|
123
|
+
yield call(fetchIiifResourceWithAuth, url, json, options, { degraded, failure, success });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Record the response (potentially kicking off other auth flows)
|
|
128
|
+
yield put((degraded || success)({ json, response, tokenServiceId }));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** */
|
|
132
|
+
export function* fetchManifest({ manifestId }) {
|
|
133
|
+
const callbacks = {
|
|
134
|
+
failure: ({ error, json, response }) => receiveManifestFailure(manifestId, typeof error === 'object' ? String(error) : error),
|
|
135
|
+
success: ({ json, response }) => receiveManifest(manifestId, json),
|
|
136
|
+
};
|
|
137
|
+
const dispatch = yield call(fetchIiifResource, manifestId, {}, callbacks);
|
|
138
|
+
yield put(dispatch);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** @private */
|
|
142
|
+
function* getAccessTokenService(resource) {
|
|
143
|
+
const manifestoCompatibleResource = resource && resource.__jsonld ? resource : { ...resource, options: {} };
|
|
144
|
+
const services = Utils.getServices(manifestoCompatibleResource).filter((s) =>
|
|
145
|
+
s.getProfile().match(/http:\/\/iiif.io\/api\/auth\//),
|
|
146
|
+
);
|
|
147
|
+
if (services.length === 0) return undefined;
|
|
148
|
+
|
|
149
|
+
const accessTokens = yield select(getAccessTokens);
|
|
150
|
+
if (!accessTokens) return undefined;
|
|
151
|
+
|
|
152
|
+
for (let i = 0; i < services.length; i += 1) {
|
|
153
|
+
const authService = services[i];
|
|
154
|
+
const accessTokenService =
|
|
155
|
+
Utils.getService(authService, 'http://iiif.io/api/auth/1/token') ||
|
|
156
|
+
Utils.getService(authService, 'http://iiif.io/api/auth/0/token');
|
|
157
|
+
const token = accessTokenService && accessTokens[accessTokenService.id];
|
|
158
|
+
if (token && token.json) return token;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** @private */
|
|
165
|
+
export function* fetchInfoResponse({ imageResource, infoId, windowId }) {
|
|
166
|
+
let iiifResource = imageResource;
|
|
167
|
+
if (!iiifResource) {
|
|
168
|
+
iiifResource = yield select(selectInfoResponse, { infoId });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const callbacks = {
|
|
172
|
+
degraded: ({ json, response, tokenServiceId }) =>
|
|
173
|
+
receiveDegradedInfoResponse(infoId, json, response.ok, tokenServiceId, windowId),
|
|
174
|
+
failure: ({ error, json, response, tokenServiceId }) => receiveInfoResponseFailure(infoId, error, tokenServiceId),
|
|
175
|
+
success: ({ json, response, tokenServiceId }) => receiveInfoResponse(infoId, json, response.ok, tokenServiceId),
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
yield call(fetchIiifResourceWithAuth, `${infoId.replace(/\/$/, '')}/info.json`, iiifResource, {}, callbacks);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** @private */
|
|
182
|
+
export function* fetchSearchResponse({ windowId, companionWindowId, query, searchId }) {
|
|
183
|
+
const callbacks = {
|
|
184
|
+
failure: ({ error, json, response }) => receiveSearchFailure(windowId, companionWindowId, searchId, error),
|
|
185
|
+
success: ({ json, response }) => receiveSearch(windowId, companionWindowId, searchId, json),
|
|
186
|
+
};
|
|
187
|
+
const dispatch = yield call(fetchIiifResource, searchId, {}, callbacks);
|
|
188
|
+
yield put(dispatch);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** @private */
|
|
192
|
+
export function* fetchAnnotation({ targetId, annotationId }) {
|
|
193
|
+
const callbacks = {
|
|
194
|
+
failure: ({ error, json, response }) => receiveAnnotationFailure(targetId, annotationId, error),
|
|
195
|
+
success: ({ json, response }) => receiveAnnotation(targetId, annotationId, json),
|
|
196
|
+
};
|
|
197
|
+
const dispatch = yield call(fetchIiifResource, annotationId, {}, callbacks);
|
|
198
|
+
yield put(dispatch);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** */
|
|
202
|
+
export function* fetchResourceManifest({ manifestId, manifestJson }) {
|
|
203
|
+
if (manifestJson) {
|
|
204
|
+
yield put(receiveManifest(manifestId, manifestJson));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!manifestId) return;
|
|
209
|
+
|
|
210
|
+
const manifests = yield select(getManifests) || {};
|
|
211
|
+
if (!manifests[manifestId]) yield* fetchManifest({ manifestId });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** */
|
|
215
|
+
export function* fetchManifests(...manifestIds) {
|
|
216
|
+
const manifests = yield select(getManifests);
|
|
217
|
+
|
|
218
|
+
for (let i = 0; i < manifestIds.length; i += 1) {
|
|
219
|
+
const manifestId = manifestIds[i];
|
|
220
|
+
if (!manifests[manifestId]) yield call(fetchManifest, { manifestId });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** */
|
|
225
|
+
export default function* iiifSaga() {
|
|
226
|
+
yield all([
|
|
227
|
+
takeEvery(ActionTypes.REQUEST_MANIFEST, fetchManifest),
|
|
228
|
+
takeEvery(ActionTypes.REQUEST_INFO_RESPONSE, fetchInfoResponse),
|
|
229
|
+
takeEvery(ActionTypes.REQUEST_SEARCH, fetchSearchResponse),
|
|
230
|
+
takeEvery(ActionTypes.REQUEST_ANNOTATION, fetchAnnotation),
|
|
231
|
+
takeEvery(ActionTypes.ADD_RESOURCE, fetchResourceManifest),
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { all, call, spawn } from 'redux-saga/effects';
|
|
2
|
+
|
|
3
|
+
import appSaga from './app';
|
|
4
|
+
import iiifSaga from './iiif';
|
|
5
|
+
import windowSaga from './windows';
|
|
6
|
+
import annotationsSaga from './annotations';
|
|
7
|
+
import authSaga from './auth';
|
|
8
|
+
|
|
9
|
+
/** */
|
|
10
|
+
function* launchSaga(saga) {
|
|
11
|
+
while (true) {
|
|
12
|
+
try {
|
|
13
|
+
yield call(saga);
|
|
14
|
+
break;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.log(e);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** */
|
|
22
|
+
function getRootSaga(pluginSagas = []) {
|
|
23
|
+
return function* rootSaga() {
|
|
24
|
+
const sagas = [annotationsSaga, appSaga, iiifSaga, windowSaga, authSaga, ...pluginSagas];
|
|
25
|
+
|
|
26
|
+
yield all(sagas.map((saga) => spawn(launchSaga, saga)));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default getRootSaga;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { all, call, put, select, takeEvery } from 'redux-saga/effects';
|
|
2
|
+
import ActionTypes from '../actions/action-types';
|
|
3
|
+
import {
|
|
4
|
+
setContentSearchCurrentAnnotation,
|
|
5
|
+
selectAnnotation,
|
|
6
|
+
setWorkspaceViewportPosition,
|
|
7
|
+
updateWindow,
|
|
8
|
+
setCanvas,
|
|
9
|
+
fetchSearch,
|
|
10
|
+
receiveManifest,
|
|
11
|
+
fetchInfoResponse,
|
|
12
|
+
showCollectionDialog,
|
|
13
|
+
} from '../actions';
|
|
14
|
+
import {
|
|
15
|
+
getSearchForWindow,
|
|
16
|
+
getSearchAnnotationsForCompanionWindow,
|
|
17
|
+
getCanvasGrouping,
|
|
18
|
+
getWindow,
|
|
19
|
+
getManifestoInstance,
|
|
20
|
+
getCompanionWindowIdsForPosition,
|
|
21
|
+
getManifestSearchService,
|
|
22
|
+
getCanvasForAnnotation,
|
|
23
|
+
getSelectedContentSearchAnnotationIds,
|
|
24
|
+
getSortedSearchAnnotationsForCompanionWindow,
|
|
25
|
+
getVisibleCanvasIds,
|
|
26
|
+
getWorkspace,
|
|
27
|
+
getElasticLayout,
|
|
28
|
+
getCanvases,
|
|
29
|
+
selectInfoResponses,
|
|
30
|
+
getWindowConfig,
|
|
31
|
+
getMiradorCanvasWrapper,
|
|
32
|
+
getMiradorManifestWrapper,
|
|
33
|
+
} from '../selectors';
|
|
34
|
+
import { fetchManifests } from './iiif';
|
|
35
|
+
import { getIiifResourceImageService } from '../../lib/iiif';
|
|
36
|
+
|
|
37
|
+
/** */
|
|
38
|
+
export function* fetchWindowManifest(action) {
|
|
39
|
+
const { collectionPath, id, manifestId } = action.payload || action.window;
|
|
40
|
+
|
|
41
|
+
if (!manifestId) return;
|
|
42
|
+
|
|
43
|
+
if (action.manifest) {
|
|
44
|
+
yield put(receiveManifest(manifestId, action.manifest));
|
|
45
|
+
} else {
|
|
46
|
+
yield call(fetchManifests, manifestId, ...(collectionPath || []));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
yield call(setWindowStartingCanvas, action);
|
|
50
|
+
yield call(setWindowDefaultSearchQuery, action);
|
|
51
|
+
if (!collectionPath) {
|
|
52
|
+
yield call(setCollectionPath, { manifestId, windowId: action.id || action.window.id });
|
|
53
|
+
}
|
|
54
|
+
yield call(determineAndShowCollectionDialog, manifestId, id);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** */
|
|
58
|
+
export function* setCanvasOnNewSequence(action) {
|
|
59
|
+
const windowId = action.id;
|
|
60
|
+
if (!action || !action.payload || !action.payload.sequenceId) return;
|
|
61
|
+
|
|
62
|
+
const canvases = yield select(getCanvases, { windowId });
|
|
63
|
+
if (!canvases || !canvases[0] || !canvases[0].id) return;
|
|
64
|
+
|
|
65
|
+
const thunk = yield call(setCanvas, windowId, canvases[0].id);
|
|
66
|
+
yield put(thunk);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** */
|
|
70
|
+
export function* setCollectionPath({ manifestId, windowId }) {
|
|
71
|
+
const manifestoInstance = yield select(getManifestoInstance, { manifestId });
|
|
72
|
+
|
|
73
|
+
if (manifestoInstance) {
|
|
74
|
+
const partOfs = manifestoInstance.getProperty('partOf');
|
|
75
|
+
const partOf = Array.isArray(partOfs) ? partOfs[0] : partOfs;
|
|
76
|
+
|
|
77
|
+
if (partOf && partOf.id) {
|
|
78
|
+
yield put(updateWindow(windowId, { collectionPath: [partOf.id] }));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** */
|
|
84
|
+
export function* fetchCollectionManifests(action) {
|
|
85
|
+
const { collectionPath } = action.payload;
|
|
86
|
+
if (!collectionPath) return;
|
|
87
|
+
|
|
88
|
+
yield call(fetchManifests, ...collectionPath);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** @private */
|
|
92
|
+
export function* setWindowStartingCanvas(action) {
|
|
93
|
+
const { canvasId, canvasIndex, manifestId } = action.payload || action.window;
|
|
94
|
+
|
|
95
|
+
const windowId = action.id || action.window.id;
|
|
96
|
+
|
|
97
|
+
if (canvasId) {
|
|
98
|
+
// Preserve viewport when initialViewerConfig exists, event if the preserveViewport OSD setting is set to false
|
|
99
|
+
const preserveViewport = !!action.payload || !!action.window?.initialViewerConfig;
|
|
100
|
+
// When canvasId is explicitly provided, always pass preserveViewport flag
|
|
101
|
+
const thunk = yield call(setCanvas, windowId, canvasId, null, { preserveViewport });
|
|
102
|
+
yield put(thunk);
|
|
103
|
+
} else {
|
|
104
|
+
const getMiradorManifest = yield select(getMiradorManifestWrapper);
|
|
105
|
+
const manifestoInstance = yield select(getManifestoInstance, { manifestId });
|
|
106
|
+
if (manifestoInstance) {
|
|
107
|
+
// set the startCanvas
|
|
108
|
+
const miradorManifest = getMiradorManifest(manifestoInstance);
|
|
109
|
+
const startCanvas =
|
|
110
|
+
miradorManifest.startCanvas || miradorManifest.canvasAt(canvasIndex || 0) || miradorManifest.canvasAt(0);
|
|
111
|
+
if (startCanvas) {
|
|
112
|
+
const preserveViewport = !!action.payload || !!action.window?.initialViewerConfig;
|
|
113
|
+
// When canvas is calculated, only pass preserveViewport when true
|
|
114
|
+
const thunk = preserveViewport
|
|
115
|
+
? yield call(setCanvas, windowId, startCanvas.id, null, { preserveViewport })
|
|
116
|
+
: yield call(setCanvas, windowId, startCanvas.id);
|
|
117
|
+
yield put(thunk);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @private */
|
|
124
|
+
export function* setWindowDefaultSearchQuery(action) {
|
|
125
|
+
// only for a brand new window
|
|
126
|
+
if (!action.window || !action.window.defaultSearchQuery) return;
|
|
127
|
+
|
|
128
|
+
const { id: windowId, defaultSearchQuery } = action.window;
|
|
129
|
+
const searchService = yield select(getManifestSearchService, { windowId });
|
|
130
|
+
const companionWindowIds = yield select(getCompanionWindowIdsForPosition, {
|
|
131
|
+
position: 'left',
|
|
132
|
+
windowId,
|
|
133
|
+
});
|
|
134
|
+
const companionWindowId = companionWindowIds[0];
|
|
135
|
+
|
|
136
|
+
if (searchService && companionWindowId) {
|
|
137
|
+
const searchId = searchService && `${searchService.id}?${new URLSearchParams({ q: defaultSearchQuery })}`;
|
|
138
|
+
yield put(fetchSearch(windowId, companionWindowId, searchId, defaultSearchQuery));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @private */
|
|
143
|
+
export function getAnnotationsBySearch(state, { canvasIds, companionWindowIds, windowId }) {
|
|
144
|
+
const annotationBySearch = companionWindowIds.reduce((accumulator, companionWindowId) => {
|
|
145
|
+
const annotations = getSearchAnnotationsForCompanionWindow(state, {
|
|
146
|
+
companionWindowId,
|
|
147
|
+
windowId,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const resourceAnnotations = annotations.resources;
|
|
151
|
+
const hitAnnotation = resourceAnnotations.find((r) => canvasIds.includes(r.targetId));
|
|
152
|
+
|
|
153
|
+
// eslint-disable-next-line no-param-reassign
|
|
154
|
+
if (hitAnnotation) accumulator[companionWindowId] = [hitAnnotation.id];
|
|
155
|
+
|
|
156
|
+
return accumulator;
|
|
157
|
+
}, {});
|
|
158
|
+
|
|
159
|
+
return annotationBySearch;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @private */
|
|
163
|
+
export function* setCurrentAnnotationsOnCurrentCanvas({ annotationId, windowId, visibleCanvases }) {
|
|
164
|
+
const searches = yield select(getSearchForWindow, { windowId });
|
|
165
|
+
const companionWindowIds = Object.keys(searches || {});
|
|
166
|
+
if (companionWindowIds.length === 0) return;
|
|
167
|
+
|
|
168
|
+
const annotationBySearch = yield select(getAnnotationsBySearch, {
|
|
169
|
+
canvasIds: visibleCanvases,
|
|
170
|
+
companionWindowIds,
|
|
171
|
+
windowId,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
yield all(
|
|
175
|
+
Object.keys(annotationBySearch).map((companionWindowId) =>
|
|
176
|
+
put(setContentSearchCurrentAnnotation(windowId, companionWindowId, annotationBySearch[companionWindowId])),
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (Object.values(annotationBySearch).length > 0) {
|
|
181
|
+
// if the currently selected annotation isn't on this canvas, do a thing.
|
|
182
|
+
yield put(selectAnnotation(windowId, Object.values(annotationBySearch)[0][0]));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** @private */
|
|
187
|
+
export function* panToFocusedWindow({ pan, windowId }) {
|
|
188
|
+
if (!pan) return;
|
|
189
|
+
const elasticLayout = yield select(getElasticLayout);
|
|
190
|
+
const { x, y, width, height } = elasticLayout[windowId] || {};
|
|
191
|
+
|
|
192
|
+
const {
|
|
193
|
+
viewportPosition: { width: viewWidth, height: viewHeight },
|
|
194
|
+
} = yield select(getWorkspace);
|
|
195
|
+
|
|
196
|
+
yield put(
|
|
197
|
+
setWorkspaceViewportPosition({
|
|
198
|
+
x: x + width / 2 - viewWidth / 2,
|
|
199
|
+
y: y + height / 2 - viewHeight / 2,
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** @private */
|
|
205
|
+
export function* updateVisibleCanvases({ windowId }) {
|
|
206
|
+
const { canvasId } = yield select(getWindow, { windowId });
|
|
207
|
+
const visibleCanvases = yield select(getCanvasGrouping, { canvasId, windowId });
|
|
208
|
+
yield put(updateWindow(windowId, { visibleCanvases: (visibleCanvases || []).map((c) => c.id) }));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** @private */
|
|
212
|
+
export function* setCanvasOfFirstSearchResult({ companionWindowId, windowId }) {
|
|
213
|
+
const { switchCanvasOnSearch } = yield select(getWindowConfig, { windowId });
|
|
214
|
+
if (!switchCanvasOnSearch) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const selectedIds = yield select(getSelectedContentSearchAnnotationIds, {
|
|
218
|
+
companionWindowId,
|
|
219
|
+
windowId,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
if (selectedIds.length !== 0) return;
|
|
223
|
+
|
|
224
|
+
const annotations = yield select(getSortedSearchAnnotationsForCompanionWindow, {
|
|
225
|
+
companionWindowId,
|
|
226
|
+
windowId,
|
|
227
|
+
});
|
|
228
|
+
if (!annotations || annotations.length === 0) return;
|
|
229
|
+
|
|
230
|
+
yield put(selectAnnotation(windowId, annotations[0].id));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** @private */
|
|
234
|
+
export function* setCanvasforSelectedAnnotation({ annotationId, windowId }) {
|
|
235
|
+
const canvasIds = yield select(getVisibleCanvasIds, { windowId });
|
|
236
|
+
const canvas = yield select(getCanvasForAnnotation, {
|
|
237
|
+
annotationId,
|
|
238
|
+
windowId,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
if (!canvas || canvasIds.includes(canvas.id)) return;
|
|
242
|
+
|
|
243
|
+
const thunk = yield call(setCanvas, windowId, canvas.id);
|
|
244
|
+
yield put(thunk);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Fetch info responses for the visible canvases */
|
|
248
|
+
export function* fetchInfoResponses({ visibleCanvases: visibleCanvasIds, windowId }) {
|
|
249
|
+
const canvases = yield select(getCanvases, { windowId });
|
|
250
|
+
const infoResponses = yield select(selectInfoResponses);
|
|
251
|
+
const visibleCanvases = (canvases || []).filter((c) => visibleCanvasIds.includes(c.id));
|
|
252
|
+
const getMiradorCanvas = yield select(getMiradorCanvasWrapper);
|
|
253
|
+
|
|
254
|
+
yield all(
|
|
255
|
+
visibleCanvases.map((canvas) => {
|
|
256
|
+
const miradorCanvas = getMiradorCanvas(canvas);
|
|
257
|
+
return all(
|
|
258
|
+
miradorCanvas.iiifImageResources
|
|
259
|
+
.map(
|
|
260
|
+
(imageResource) =>
|
|
261
|
+
!infoResponses[getIiifResourceImageService(imageResource)?.id] &&
|
|
262
|
+
put(fetchInfoResponse({ imageResource, windowId })),
|
|
263
|
+
)
|
|
264
|
+
.filter(Boolean),
|
|
265
|
+
);
|
|
266
|
+
}),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** */
|
|
271
|
+
export function* determineAndShowCollectionDialog(manifestId, windowId) {
|
|
272
|
+
const manifestoInstance = yield select(getManifestoInstance, { manifestId });
|
|
273
|
+
if (manifestoInstance && manifestoInstance.isCollection()) {
|
|
274
|
+
yield put(showCollectionDialog(manifestId, [], windowId));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** */
|
|
279
|
+
export default function* windowsSaga() {
|
|
280
|
+
yield all([
|
|
281
|
+
takeEvery(ActionTypes.ADD_WINDOW, fetchWindowManifest),
|
|
282
|
+
takeEvery(ActionTypes.UPDATE_WINDOW, fetchWindowManifest),
|
|
283
|
+
takeEvery(ActionTypes.UPDATE_WINDOW, setCanvasOnNewSequence),
|
|
284
|
+
takeEvery(ActionTypes.UPDATE_WINDOW, fetchCollectionManifests),
|
|
285
|
+
takeEvery(ActionTypes.SET_CANVAS, setCurrentAnnotationsOnCurrentCanvas),
|
|
286
|
+
takeEvery(ActionTypes.SET_CANVAS, fetchInfoResponses),
|
|
287
|
+
takeEvery(ActionTypes.UPDATE_COMPANION_WINDOW, fetchCollectionManifests),
|
|
288
|
+
takeEvery(ActionTypes.SET_WINDOW_VIEW_TYPE, updateVisibleCanvases),
|
|
289
|
+
takeEvery(ActionTypes.RECEIVE_SEARCH, setCanvasOfFirstSearchResult),
|
|
290
|
+
takeEvery(ActionTypes.SELECT_ANNOTATION, setCanvasforSelectedAnnotation),
|
|
291
|
+
takeEvery(ActionTypes.FOCUS_WINDOW, panToFocusedWindow),
|
|
292
|
+
]);
|
|
293
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { createSelector } from 'reselect';
|
|
2
|
+
import filter from 'lodash/filter';
|
|
3
|
+
import AnnotationFactory from '../../lib/AnnotationFactory';
|
|
4
|
+
import { miradorSlice } from './utils';
|
|
5
|
+
import { getCanvas, getVisibleCanvasIds } from './canvases';
|
|
6
|
+
import { getConfig } from './config';
|
|
7
|
+
import { getWindow } from './getters';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns the annotation object from the mirador slice.
|
|
11
|
+
* @param {object} state redux state
|
|
12
|
+
* @returns {object} Annotations from the state
|
|
13
|
+
*/
|
|
14
|
+
export const getAnnotations = (state) => miradorSlice(state).annotations;
|
|
15
|
+
|
|
16
|
+
const getMotivations = createSelector(
|
|
17
|
+
[getConfig, (state, { motivations }) => motivations],
|
|
18
|
+
(config, motivations) => motivations || config.annotations.filteredMotivations,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const getAnnotationsOnCanvas = createSelector([getCanvas, getAnnotations], (canvas, annotations) => {
|
|
22
|
+
if (!annotations || !canvas) return [];
|
|
23
|
+
if (!annotations[canvas.id]) return [];
|
|
24
|
+
|
|
25
|
+
return Object.values(annotations[canvas.id]).flat();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const getPresentAnnotationsCanvas = createSelector([getAnnotationsOnCanvas], (annotations) =>
|
|
29
|
+
filter(
|
|
30
|
+
Object.values(annotations).map((annotation) => annotation && AnnotationFactory.determineAnnotation(annotation.json)),
|
|
31
|
+
(annotation) => annotation && annotation.present(),
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const getAnnotationsOnSelectedCanvases = createSelector(
|
|
36
|
+
[(state, { canvasId, ...otherProps }) => (canvasId ? [canvasId] : getVisibleCanvasIds(state, otherProps)), getAnnotations],
|
|
37
|
+
(canvasIds, annotations) => {
|
|
38
|
+
if (!annotations || canvasIds.length === 0) return [];
|
|
39
|
+
return canvasIds.flatMap((targetId) => annotations[targetId] && Object.values(annotations[targetId]));
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns an array of present annotations given a canvasId.
|
|
45
|
+
* @param {object} state redux state
|
|
46
|
+
* @param {string} canvasId canvasId
|
|
47
|
+
* @returns {Array} An array of present annotations
|
|
48
|
+
*/
|
|
49
|
+
export const getPresentAnnotationsOnSelectedCanvases = createSelector([getAnnotationsOnSelectedCanvases], (annotations) =>
|
|
50
|
+
filter(
|
|
51
|
+
Object.values(annotations).map((annotation) => annotation && AnnotationFactory.determineAnnotation(annotation.json)),
|
|
52
|
+
(annotation) => annotation && annotation.present(),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns an array of annotation resources filtered by the given motivation for a particular canvas.
|
|
58
|
+
* @param {Array} annotations
|
|
59
|
+
* @param {Array} motivations
|
|
60
|
+
* @returns {Array}
|
|
61
|
+
*/
|
|
62
|
+
export const getAnnotationResourcesByMotivationForCanvas = createSelector(
|
|
63
|
+
[getPresentAnnotationsCanvas, getMotivations],
|
|
64
|
+
(annotations, motivations) => {
|
|
65
|
+
const resources = annotations.flatMap((annotation) => annotation.resources);
|
|
66
|
+
|
|
67
|
+
// If motivations is empty, null, or undefined, return everything
|
|
68
|
+
if (!motivations || motivations.length === 0) {
|
|
69
|
+
return resources;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Otherwise filter by motivations
|
|
73
|
+
return resources.filter((resource) => resource.motivations.some((motivation) => motivations.includes(motivation)));
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Returns annotation resources for a canvas destructured into their id/content/tags/targetId.
|
|
79
|
+
* @param {object} state
|
|
80
|
+
* @param {object} props
|
|
81
|
+
* @param {string} props.canvasId
|
|
82
|
+
* @param {string} props.windowId
|
|
83
|
+
* @returns {Array} [{ id: 'abc123', content: 'Annotation Content' }, ...]
|
|
84
|
+
*/
|
|
85
|
+
export const getAnnotationResourcesDataForCanvas = createSelector([getAnnotationResourcesByMotivationForCanvas], (resources) =>
|
|
86
|
+
resources.map((resource) => ({
|
|
87
|
+
content: resource.chars,
|
|
88
|
+
id: resource.id,
|
|
89
|
+
tags: resource.tags,
|
|
90
|
+
targetId: resource.targetId,
|
|
91
|
+
})),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns an array of annotation resources filtered by the given motivation.
|
|
96
|
+
* @param {Array} annotations
|
|
97
|
+
* @param {Array} motivations
|
|
98
|
+
* @returns {Array}
|
|
99
|
+
*/
|
|
100
|
+
export const getAnnotationResourcesByMotivation = createSelector(
|
|
101
|
+
[getPresentAnnotationsOnSelectedCanvases, getMotivations],
|
|
102
|
+
(annotations, motivations) => {
|
|
103
|
+
const resources = annotations.flatMap((annotation) => annotation.resources);
|
|
104
|
+
|
|
105
|
+
// If motivations is empty, null, or undefined, return everything
|
|
106
|
+
if (!motivations || motivations.length === 0) {
|
|
107
|
+
return resources;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Otherwise filter by motivations
|
|
111
|
+
return resources.filter((resource) => resource.motivations.some((motivation) => motivations.includes(motivation)));
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns the selected annotations IDs.
|
|
117
|
+
* @param {object} state
|
|
118
|
+
* @param {string} windowId
|
|
119
|
+
* @param {Array} targetIds
|
|
120
|
+
* @returns {Array}
|
|
121
|
+
*/
|
|
122
|
+
export const getSelectedAnnotationId = createSelector([getWindow], ({ selectedAnnotationId }) => selectedAnnotationId);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns annotations on selected canvases.
|
|
126
|
+
* @param {object} state
|
|
127
|
+
* @returns {Array}
|
|
128
|
+
*/
|
|
129
|
+
export const getSelectedAnnotationsOnCanvases = createSelector(
|
|
130
|
+
[getPresentAnnotationsOnSelectedCanvases, getSelectedAnnotationId],
|
|
131
|
+
(canvasAnnotations, selectedAnnotationId) =>
|
|
132
|
+
canvasAnnotations
|
|
133
|
+
.map((annotation) => ({
|
|
134
|
+
id: annotation['@id'] || annotation.id,
|
|
135
|
+
resources: annotation.resources.filter((r) => selectedAnnotationId === r.id),
|
|
136
|
+
}))
|
|
137
|
+
.filter((val) => val.resources.length > 0),
|
|
138
|
+
);
|