From c08582211c6b78bf48722ba39ca769fedbbfbc09 Mon Sep 17 00:00:00 2001 From: dnoneill Date: Fri, 13 Dec 2024 11:08:53 -0500 Subject: [PATCH] make sul-embed work with exhibits select image section --- app/components/embed/m3_component.html.erb | 1 + app/controllers/embed_controller.rb | 2 +- app/javascript/src/modules/m3_viewer.js | 42 +++++++++++++++++++++- app/javascript/src/plugins/xywhPlugin.js | 32 +++++++++++++++-- app/viewers/embed/viewer/m3_viewer.rb | 3 +- app/views/embed/iiif.html.erb | 1 + lib/embed/request.rb | 7 +++- 7 files changed, 81 insertions(+), 7 deletions(-) diff --git a/app/components/embed/m3_component.html.erb b/app/components/embed/m3_component.html.erb index 576076b49..39ffe10ed 100644 --- a/app/components/embed/m3_component.html.erb +++ b/app/components/embed/m3_component.html.erb @@ -4,6 +4,7 @@ id='sul-embed-m3' class='m3' data-m3-uri='<%= viewer.manifest_json_url %>' + data-viewer-config='<%= viewer.iiif_initial_viewer_config %>' data-canvas-id='<%= viewer.canvas_id %>' data-canvas-index='<%= viewer.canvas_index %>' data-hide-title='<%= viewer.embed_request.hide_title? %>' diff --git a/app/controllers/embed_controller.rb b/app/controllers/embed_controller.rb index b926612cb..45c1d5de7 100644 --- a/app/controllers/embed_controller.rb +++ b/app/controllers/embed_controller.rb @@ -54,7 +54,7 @@ def linted_params rescue URI::InvalidURIError raise ActionController::BadRequest end - params.permit(:url, :maxwidth, :maxheight, :format, :fullheight, :new_component, + params.permit(:url, :maxwidth, :maxheight, :format, :fullheight, :new_component, :iiif_initial_viewer_config, :hide_title, :hide_embed, :hide_download, :hide_search, :min_files_to_search, :canvas_id, :canvas_index, :search, :suggested_search, :image_tools, :cdl_hold_record_id) end diff --git a/app/javascript/src/modules/m3_viewer.js b/app/javascript/src/modules/m3_viewer.js index 1ef45a587..f12faf397 100644 --- a/app/javascript/src/modules/m3_viewer.js +++ b/app/javascript/src/modules/m3_viewer.js @@ -11,6 +11,8 @@ import miradorZoomBugPlugin from '../plugins/miradorZoomBugPlugin' import embedModePlugin from '../plugins/embedModePlugin' import analyticsPlugin from '../plugins/analyticsPlugin' import cdlAuthPlugin from '../plugins/cdlAuthPlugin' +import xywhPlugin from '../plugins/xywhPlugin' +import { getExportableState } from 'mirador/dist/es/src/state/selectors' export default { init: function() { @@ -30,7 +32,10 @@ export default { sideBarPanel = 'attribution' } - Mirador.viewer({ + let viewerConfig + if (data.viewerConfig && data.viewerConfig !== 'undefined') { viewerConfig = JSON.parse(decodeURIComponent(data.viewerConfig)) } + + const viewerInstance = Mirador.viewer({ id: 'sul-embed-m3', miradorDownloadPlugin: { restrictDownloadOnSizeDefinition: true, @@ -80,6 +85,7 @@ export default { suggestedSearches: data.suggestedSearch.length > 0 ? [data.suggestedSearch] : null, loadedManifest: data.m3Uri, canvasIndex: Number(data.canvasIndex), + initialViewerConfig: viewerConfig, canvasId: data.canvasId, ...(cdl && { cdl: { @@ -135,5 +141,39 @@ export default { analyticsPlugin, xywhPlugin, ].filter(Boolean)) + + window.addEventListener('message', (event) => { + const regex = /^(stanford\.edu|[\w-]+\.stanford\.edu)$/ + if (regex.exec(event.origin) === null && process.env.RAILS_ENV !== 'development') { + return + } + + if (event && event.data) { + let parsedData + try { + parsedData = typeof event.data === 'string' ? JSON.parse(event.data) : event.data + } catch (error) { + console.error('Failed to parse event data:', error) + return // Exit if parsing fails + } + if (parsedData.type === "requestState") { + const currentState = viewerInstance.store.getState() + const exportableState = getExportableState(currentState) + + const imageUrl = viewerInstance.container.querySelector('[data-full-image]').dataset.fullImage.split('*') + const canvasIndex = viewerInstance.container.querySelector('.mirador-canvas-count').textContent.split(' of')[0] + + // Send the state back to the parent window + window.parent.postMessage( + JSON.stringify({ + type: 'stateResponse', + data: {...exportableState, ...{'iiif_images': imageUrl, 'canvas_index': canvasIndex}}, + source: 'sul-embed-m3', + }), + event.origin + ) + } + } + }) } } diff --git a/app/javascript/src/plugins/xywhPlugin.js b/app/javascript/src/plugins/xywhPlugin.js index 3d3c81d38..83981432f 100644 --- a/app/javascript/src/plugins/xywhPlugin.js +++ b/app/javascript/src/plugins/xywhPlugin.js @@ -6,13 +6,39 @@ const convertToIIIFCoords = (bounds) => { return Math.round(bounds); }; +const convertToRegionUrl = (imageBounds, image_url) => { + const xywh = `${convertToIIIFCoords(imageBounds.x)},${convertToIIIFCoords(imageBounds.y)},${convertToIIIFCoords(imageBounds.width)},${convertToIIIFCoords(imageBounds.height)}`; + return image_url + `/${xywh}/full/0/default.jpg` +}; + const onViewportChange = (event) => { const viewer = event.eventSource; const { viewport } = viewer; - const imageBounds = viewport.viewportToImageRectangle(viewport.getBounds()); - const parsedBounds = `${convertToIIIFCoords(imageBounds.x)},${convertToIIIFCoords(imageBounds.y)},${convertToIIIFCoords(imageBounds.width)},${convertToIIIFCoords(imageBounds.height)}`; - viewer.element.parentNode.setAttribute('data-xywh-coords', parsedBounds); + let full_image = '' + const itemCount = viewport.viewer.world.getItemCount(); + + if (itemCount > 1){ + const page1 = viewport.viewer.world.getItemAt(0); + const page2 = viewport.viewer.world.getItemAt(1); + const page1_vars = {x: 0, y: 0, height: page1.source.height, width: page1.source.width, id: page1.source._id} + const page2_vars = {x: page1_vars['width'], y: page1_vars['height'], height: page2.source.height, width: page2.source.width, id: page2.source._id} + let page1_bounds = page1.viewportToImageRectangle(viewport.getBounds()); + let page2_bounds = page2.viewportToImageRectangle(viewport.getBounds()); + let visible_pages =[] + if (page1_bounds.x <= page1.source.width){ + visible_pages.push(convertToRegionUrl(page1_bounds, page1.source._id)) + } + if (page1.source.width - page1_bounds.x < page1_bounds.width || page2_bounds.x > 0) { + page2_bounds.width = page2_bounds.width - (page1.source.width - page1_bounds.x); + visible_pages.push(convertToRegionUrl(page2_bounds, page2.source._id)) + } + full_image = visible_pages.join("*") + } else { + const imageBounds = viewport.viewportToImageRectangle(viewport.getBounds()); + full_image = convertToRegionUrl(imageBounds, viewport.viewer.source._id) + } + viewer.element.parentNode.setAttribute('data-full-image', full_image); }; function XywhDataAttributePlugin({ viewer, windowId }) { diff --git a/app/viewers/embed/viewer/m3_viewer.rb b/app/viewers/embed/viewer/m3_viewer.rb index fb541ed02..666670972 100644 --- a/app/viewers/embed/viewer/m3_viewer.rb +++ b/app/viewers/embed/viewer/m3_viewer.rb @@ -3,7 +3,8 @@ module Embed module Viewer class M3Viewer < CommonViewer - delegate :search, :suggested_search, :canvas_id, :cdl_hold_record_id, to: :embed_request + delegate :search, :suggested_search, :canvas_id, :cdl_hold_record_id, :iiif_initial_viewer_config, + to: :embed_request def component M3Component diff --git a/app/views/embed/iiif.html.erb b/app/views/embed/iiif.html.erb index 196fb710e..6b8587e52 100644 --- a/app/views/embed/iiif.html.erb +++ b/app/views/embed/iiif.html.erb @@ -32,6 +32,7 @@ data-search='<%= @embed_request.search %>' data-suggested-search='<%= @embed_request.suggested_search %>' data-image-tools='<%= @embed_request.image_tools %>' + data-viewer-config='<%= @embed_request.iiif_initial_viewer_config %>' style='height:100%; width:100%'> diff --git a/lib/embed/request.rb b/lib/embed/request.rb index f80a22c0e..cf5fbaa8f 100644 --- a/lib/embed/request.rb +++ b/lib/embed/request.rb @@ -77,7 +77,8 @@ def as_url_params :min_files_to_search, :canvas_id, :canvas_index, :search, :suggested_search, - :image_tools + :image_tools, + :iiif_initial_viewer_config ) if p.respond_to? :permit! @@ -107,6 +108,10 @@ def image_tools params[:image_tools] end + def iiif_initial_viewer_config + params[:iiif_initial_viewer_config] + end + def validate!(url_parameter: true, url_scheme: true, format: true) require_url_parameter if url_parameter validate_url_scheme if url_scheme