Skip to content

Commit

Permalink
Canvas metadata (#311)
Browse files Browse the repository at this point in the history
* Implement reading Canvas-level metadata for MetadataDisplay component

* Add prop to MetadataDisplay comp. to enable displaying both Canvas and Manifest metadata

* Fix usage of displayTitle prop with new props

* Update src/services/iiif-parser.test.js

Co-authored-by: Chris Colvard <[email protected]>

* Changes from feedback in code-review

---------

Co-authored-by: Chris Colvard <[email protected]>
  • Loading branch information
Dananji and cjcolvar authored Dec 15, 2023
1 parent 2942572 commit 501af72
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 105 deletions.
175 changes: 139 additions & 36 deletions src/components/MetadataDisplay/MetadataDisplay.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,162 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useManifestState } from '../../context/manifest-context';
import { parseMetadata } from '@Services/iiif-parser';
import { getMetadata } from '@Services/iiif-parser';
import './MetadataDisplay.scss';

const MetadataDisplay = ({ displayTitle = true, showHeading = true }) => {
const { manifest } = useManifestState();
/**
* @param {Boolean} param0 display only Canvas metadata when set to true with other props are default
* @param {Boolean} param1 display both Manifest and Canvas metadata when set to true
* @param {Boolean} param2 hide the title in the metadata when set to false, defaults to true
* @param {Boolean} param3 hide the heading UI component when set to false, defaults to true
* @returns
*/
const MetadataDisplay = ({
displayOnlyCanvasMetadata = false,
displayAllMetadata = false,
displayTitle = true,
showHeading = true,
itemHeading = 'Item Details',
sectionHeaading = 'Section Details',
}) => {
const { manifest, canvasIndex } = useManifestState();

const [metadata, setMetadata] = React.useState();
const [manifestMetadata, setManifestMetadata] = React.useState();
// Metadata for all Canavases in state
const [canvasesMetadata, _setCanvasesMetadata] = React.useState();
// Current Canvas metadata in state
const [canvasMetadata, setCanvasMetadata] = React.useState();
// Boolean flags set according to user props to hide/show metadata
const [showManifestMetadata, setShowManifestMetadata] = React.useState();
const [showCanvasMetadata, setShowCanvasMetadata] = React.useState();

let canvasesMetadataRef = React.useRef();
const setCanvasesMetadata = (m) => {
_setCanvasesMetadata(m);
canvasesMetadataRef.current = m;
};
/**
* On the initialization of the component read metadata from the Manifest
* and/or Canvases based on the input props and set the initial set(s) of
* metadata in the component's state
*/
React.useEffect(() => {
if (manifest) {
let parsedMetadata = parseMetadata(manifest);
if (!displayTitle) {
parsedMetadata = parsedMetadata.filter(md => md.label.toLowerCase() != 'title');
// Display Canvas metadata only when specified in the props
const showCanvas = displayOnlyCanvasMetadata || displayAllMetadata;
setShowCanvasMetadata(showCanvas);
const showManifest = !displayOnlyCanvasMetadata || displayAllMetadata;
setShowManifestMetadata(showManifest);

// Parse metadata from Manifest
const parsedMetadata = getMetadata(manifest, showCanvas);

// Set Manifest and Canvas metadata in the state variables according to props
if (showCanvas) {
setCanvasesMetadata(parsedMetadata.canvasMetadata);
setCanvasMetadataInState();
}
if (showManifest) {
let manifestMeta = parsedMetadata.manifestMetadata;
if (!displayTitle) {
manifestMeta = manifestMeta.filter(md => md.label.toLowerCase() != 'title');
}
setManifestMetadata(manifestMeta);
}
setMetadata(parsedMetadata);
}
}, [manifest]);

if (metadata && metadata.length > 0) {
return (
<div
data-testid="metadata-display"
className="ramp--metadata-display">
{showHeading && (
<div className="ramp--metadata-display-title" data-testid="metadata-display-title">
<h4>Details</h4>
</div>
)}
<div className="ramp--metadata-display-content">
{metadata.map((md, i) => {
return (
<React.Fragment key={i}>
<dt>{md.label}</dt>
<dd dangerouslySetInnerHTML={{ __html: md.value }}></dd>
</React.Fragment>
);
})
}
</div>
</div>
);
} else {
return (<div
/**
* When displaying current Canvas's metadata in the component, update the metadata
* in the component's state listening to the canvasIndex changes in the central
* state
*/
React.useEffect(() => {
if (canvasIndex >= 0 && showCanvasMetadata) {
setCanvasMetadataInState();
}
}, [canvasIndex]);

/**
* Set canvas metadata in state
*/
const setCanvasMetadataInState = () => {
let canvasData = canvasesMetadataRef.current
.filter((m) => m.canvasindex === canvasIndex)[0].metadata;
if (!displayTitle) {
canvasData = canvasData.filter(md => md.label.toLowerCase() != 'title');
}
setCanvasMetadata(canvasData);
};
/**
* Distinguish whether there is any metadata to be displayed
* @returns {Boolean}
*/
const hasMetadata = () => {
return canvasMetadata?.length > 0 || manifestMetadata?.length > 0;
};

return (
<div
data-testid="metadata-display"
className="ramp--metadata-display">
<p>No valid Metadata is in the Manifest</p>
</div>);
}
{showHeading && (
<div className="ramp--metadata-display-title" data-testid="metadata-display-title">
<h4>Details</h4>
</div>
)}
{hasMetadata() && (
<div className="ramp--metadata-display-content">
{showManifestMetadata && manifestMetadata?.length > 0 && (
<React.Fragment>
{displayAllMetadata && <p>{itemHeading}</p>}
{manifestMetadata.map((md, index) => {
return (
<React.Fragment key={index}>
<dt>{md.label}</dt>
<dd dangerouslySetInnerHTML={{ __html: md.value }}></dd>
</React.Fragment>
);
})}
</React.Fragment>
)}
{showCanvasMetadata && canvasMetadata?.length > 0 && (
<React.Fragment>
{displayAllMetadata && <p>{sectionHeaading}</p>}
{canvasMetadata.map((md, index) => {
return (
<React.Fragment key={index}>
<dt>{md.label}</dt>
<dd dangerouslySetInnerHTML={{ __html: md.value }}></dd>
</React.Fragment>
);
})}
</React.Fragment>
)}
</div>
)
}
{
!hasMetadata() && (
<div
data-testid="metadata-display-message"
className="ramp--metadata-display-message">
<p>No valid Metadata is in the Manifest/Canvas(es)</p>
</div>
)
}
</div>

);
};

MetadataDisplay.propTypes = {
displayOnlyCanvasMetadata: PropTypes.bool,
displayAllMetadata: PropTypes.bool,
displayTitle: PropTypes.bool,
showHeading: PropTypes.bool,
itemHeading: PropTypes.string,
sectionHeaading: PropTypes.string,
};

export default MetadataDisplay;
Expand Down
6 changes: 5 additions & 1 deletion src/components/MetadataDisplay/MetadataDisplay.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
MetadataDisplay component, renders any available metadata in a given IIIF manifest. This component reads manifest data from central state management provided by Contexts. Thus it should be wrapped by context providers using `IIIFPlayer` which is the component in Ramp providing these out of the box.
MetadataDisplay component, renders any available metadata in a given IIIF manifest. By default it displays metadata relevant to the Manifest, and can be customized to show Canvas level metadata using the following props. Any changes to `displayTitle` prop is applied to both Manifest and Canvas metadata. This component reads manifest data from central state management provided by Contexts. Thus it should be wrapped by context providers using `IIIFPlayer` which is the component in Ramp providing these out of the box.

`MetadataDisplay` component allows the following props;
- `displayTitle`: accepts a Boolean value, which has a default value of `true` and is _not required_. This allows to hide the title in the `MetadataDisplay` component if it's included in the metadata of the IIIF manifest. In some use-cases where the title is already visible in some other part of the page, this can be used to avoid displaying the title in multiple places.
- `showHeading`: accepts a Boolean value, which has a default value of `true` and is _not required_. This enables to hide the `Details` heading on top of the component allowing to customize the user interface.
- `displayOnlyCanvasMetadata`: accepts a Boolean value, which has a default value of `false` and is _not required_. Setting this to `true` indicates Ramp to read and display metadata for the current Canvas instead of Manifest.
- `displayAllMetadata`: accepts a Boolean value, which has a default value of `false` and is _not required_. Setting this to `true` indicates Ramp to read and display metadata relevant for both current Canvas and Manifest.
- `itemHeading`: accepts a String value, which has a default value of '`Item Details`' and is _not required_. This allows to customize the title for the Manifest level metadata list in the component.
- `sectionHeading`: accepts a String value, which has a default value of '`Section Details`' and is _not required_. This allows to customize the title for the Canvas level metadata list in the component

To import this component from the library;

Expand Down
10 changes: 9 additions & 1 deletion src/components/MetadataDisplay/MetadataDisplay.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@
}

.ramp--metadata-display-content {
padding: 0 0 1.5rem 1.5rem;
padding: 0 1.5rem 1.5rem;
color: $primaryDarker;
max-height: 30rem;
overflow-y: auto;

p {
font-weight: normal;
padding: 0.5rem 0;
margin: 00 0 0.75rem;
color: $primaryDarker;
border-bottom: 0.1rem solid $primaryDark;
}

dt {
font-weight: bold;
}
Expand Down
Loading

0 comments on commit 501af72

Please sign in to comment.