Skip to content

Commit

Permalink
Merge pull request #4054 from ProjectMirador/manifest-getValue-locale2
Browse files Browse the repository at this point in the history
Refactor manifesto initialization to push property localization down
  • Loading branch information
cbeer authored Jan 10, 2025
2 parents 3930da8 + d947941 commit 40f05d2
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 197 deletions.
1 change: 1 addition & 0 deletions __tests__/src/components/GalleryViewThumbnail.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ describe('GalleryView', () => {
describe('on-demand annotation fetching', () => {
const canvas = {
getHeight: () => 50,
getLabel: () => ({ getValue: () => 'label' }),
getServices: vi.fn(),
getThumbnail: vi.fn(),
getType: vi.fn(),
Expand Down
4 changes: 2 additions & 2 deletions __tests__/src/components/WindowSideBarCanvasPanel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ function createWrapper(props) {
let sequences;

if (props.multipleSequences) {
sequences = [{ id: 'a', label: 'seq1' },
{ id: 'b', label: 'seq2' }];
sequences = [{ getLabel: () => ({ getValue: () => undefined }), id: 'a', label: 'seq1' },
{ getLabel: () => ({ getValue: () => undefined }), id: 'b', label: 'seq2' }];
} else {
sequences = Utils.parseManifest(manifestJson).getSequences();
}
Expand Down
6 changes: 0 additions & 6 deletions __tests__/src/selectors/manifests.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ describe('getManifestoInstance', () => {
const received = getManifestoInstance(state, { manifestId: 'x' });
expect(received.id).toEqual('http://iiif.io/api/presentation/2.1/example/fixtures/19/manifest.json');
});
it('is cached based off of input props', () => {
const state = { manifests: { x: { json: manifestFixture019 } } };
const received = getManifestoInstance(state, { manifestId: 'x' });
expect(getManifestoInstance(state, { manifestId: 'x' })).toBe(received);
expect(getManifestoInstance(state, { manifestId: 'x', windowId: 'y' })).not.toBe(received);
});
});

describe('getManifestLogo()', () => {
Expand Down
21 changes: 12 additions & 9 deletions src/components/AppProviders.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import createI18nInstance from '../i18n';
import FullScreenContext from '../contexts/FullScreenContext';
import LocaleContext from '../contexts/LocaleContext';

/**
* Allow applications to opt-out of (or provide their own) drag and drop context
Expand Down Expand Up @@ -119,15 +120,17 @@ export function AppProviders({
return (
<FullScreenShim>
<StoreAwareI18nextProvider language={language} translations={translations}>
<StyledEngineProvider injectFirst>
<CacheProvider value={theme.direction === 'rtl' ? cacheRtl : cacheDefault}>
<ThemeProvider theme={createTheme((theme))}>
<MaybeDndProvider dndManager={dndManager}>
{children}
</MaybeDndProvider>
</ThemeProvider>
</CacheProvider>
</StyledEngineProvider>
<LocaleContext.Provider value={language}>
<StyledEngineProvider injectFirst>
<CacheProvider value={theme.direction === 'rtl' ? cacheRtl : cacheDefault}>
<ThemeProvider theme={createTheme((theme))}>
<MaybeDndProvider dndManager={dndManager}>
{children}
</MaybeDndProvider>
</ThemeProvider>
</CacheProvider>
</StyledEngineProvider>
</LocaleContext.Provider>
</StoreAwareI18nextProvider>
</FullScreenShim>
);
Expand Down
12 changes: 2 additions & 10 deletions src/components/CanvasLayers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next';
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
import MiradorMenuButton from '../containers/MiradorMenuButton';
import IIIFThumbnail from '../containers/IIIFThumbnail';
import { IIIFResourceLabel } from './IIIFResourceLabel';

const StyledDragHandle = styled('div')(({ theme }) => ({
alignItems: 'center',
Expand All @@ -40,15 +41,6 @@ const reorder = (list, startIndex, endIndex) => {
return result;
};

/** */
function getUseableLabel(resource, index) {
return (resource
&& resource.getLabel
&& resource.getLabel().length > 0)
? resource.getLabel().getValue()
: String(index + 1);
}

/** @private */
function Layer({
resource, layerMetadata = {}, index, handleOpacityChange, setLayerVisibility, moveToTop,
Expand Down Expand Up @@ -78,7 +70,7 @@ function Layer({
component="div"
variant="body1"
>
{getUseableLabel(resource, index)}
<IIIFResourceLabel resource={resource} fallback={index + 1} />
<div>
<MiradorMenuButton aria-label={t(layer.visibility ? 'layer_hide' : 'layer_show')} edge="start" size="small" onClick={() => { setLayerVisibility(resource.id, !layer.visibility); }}>
{ layer.visibility ? <VisibilityIcon /> : <VisibilityOffIcon /> }
Expand Down
18 changes: 5 additions & 13 deletions src/components/CollectionDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import CollapsibleSection from '../containers/CollapsibleSection';
import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
import ManifestInfo from '../containers/ManifestInfo';
import WorkspaceContext from '../contexts/WorkspaceContext';
import { IIIFResourceLabel } from './IIIFResourceLabel';

const StyledScrollIndicatedDialogContent = styled(ScrollIndicatedDialogContent)(() => ({
padding: (theme) => theme.spacing(1),
Expand All @@ -38,15 +39,6 @@ const StyledCollectionFilter = styled('div')(() => ({
paddingTop: 0,
}));

/** */
function getUseableLabel(resource, index) {
return (resource
&& resource.getLabel
&& resource.getLabel().length > 0)
? resource.getLabel().getValue()
: String(index + 1);
}

/** */
const Placeholder = ({ onClose, container }) => (
<Dialog
Expand Down Expand Up @@ -149,7 +141,7 @@ export function CollectionDialog({
{ t(isMultipart ? 'multipartCollection' : 'collection') }
</Typography>
<Typography component="div" variant="h3">
{getUseableLabel(manifest)}
<IIIFResourceLabel resource={manifest} />
</Typography>
</DialogTitle>
<StyledScrollIndicatedDialogContent>
Expand All @@ -158,7 +150,7 @@ export function CollectionDialog({
startIcon={<ArrowBackIcon />}
onClick={() => goToPreviousCollection()}
>
{getUseableLabel(collection)}
<IIIFResourceLabel resource={collection} />
</Button>
)}

Expand Down Expand Up @@ -204,7 +196,7 @@ export function CollectionDialog({
onClick={() => { selectCollection(c); }}
variant="multiline"
>
{getUseableLabel(c)}
<IIIFResourceLabel resource={c} />
</MenuItem>
))
}
Expand All @@ -219,7 +211,7 @@ export function CollectionDialog({
onClick={() => { selectManifest(m); }}
variant="multiline"
>
{getUseableLabel(m)}
<IIIFResourceLabel resource={m} />
</MenuItem>
))
}
Expand Down
157 changes: 82 additions & 75 deletions src/components/CompanionWindow.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable react/require-default-props */
import { Children, cloneElement, forwardRef } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import CloseIcon from '@mui/icons-material/CloseSharp';
Expand All @@ -14,6 +15,8 @@ import { useElementSize } from '@custom-react-hooks/use-element-size';
import mergeRefs from 'merge-refs';
import MiradorMenuButton from '../containers/MiradorMenuButton';
import ns from '../config/css-ns';
import LocaleContext from '../contexts/LocaleContext';
import { getCompanionWindowLocale } from '../state/selectors/companionWindows';

const Root = styled(Paper, { name: 'CompanionWindow', slot: 'root' })({});
const StyledToolbar = styled(Toolbar, { name: 'CompanionWindow', slot: 'toolbar' })({});
Expand All @@ -29,12 +32,13 @@ const StyledCloseButton = styled(MiradorMenuButton, { name: 'CompanionWindow', s
*/
export const CompanionWindow = forwardRef((props, innerRef) => {
const {
ariaLabel = undefined, classes = {}, direction, paperClassName = '', onCloseClick = () => {}, updateCompanionWindow = undefined, isDisplayed = false,
ariaLabel = undefined, classes = {}, direction, id, paperClassName = '', onCloseClick = () => {}, updateCompanionWindow = undefined, isDisplayed = false,
position = null, title = null, children = undefined, titleControls = null,
defaultSidebarPanelWidth = 235, defaultSidebarPanelHeight = 201,
} = props;
const [sizeRef, size] = useElementSize();
const { t } = useTranslation();
const locale = useSelector(state => getCompanionWindowLocale(state, { companionWindowId: id }), [id]);

/** */
const openInNewStyle = direction === 'rtl' ? { transform: 'scale(-1, 1)' } : {};
Expand Down Expand Up @@ -105,83 +109,85 @@ export const CompanionWindow = forwardRef((props, innerRef) => {
component="aside"
aria-label={ariaLabel || title}
>
<StyledRnd
style={{ display: 'inherit', position: 'inherit' }}
ownerState={props}
default={{
height: isBottom ? defaultSidebarPanelHeight : '100%',
width: isBottom ? 'auto' : defaultSidebarPanelWidth,
}}
disableDragging
enableResizing={resizeHandles}
minHeight={50}
minWidth={position === 'left' ? 235 : 100}
>

<StyledToolbar
variant="dense"
className={[ns('companion-window-header'), size.width < 370 ? 'test' : null].join(' ')}
disableGutters
<LocaleContext.Provider value={locale}>
<StyledRnd
style={{ display: 'inherit', position: 'inherit' }}
ownerState={props}
default={{
height: isBottom ? defaultSidebarPanelHeight : '100%',
width: isBottom ? 'auto' : defaultSidebarPanelWidth,
}}
disableDragging
enableResizing={resizeHandles}
minHeight={50}
minWidth={position === 'left' ? 235 : 100}
>
<StyledTitle variant="h3">{title}</StyledTitle>
{
position === 'left'
? updateCompanionWindow
&& (
<MiradorMenuButton
aria-label={t('openInCompanionWindow')}
onClick={() => { updateCompanionWindow({ position: 'right' }); }}
>
<OpenInNewIcon style={openInNewStyle} />
</MiradorMenuButton>
)
: (
<>
{
updateCompanionWindow && (
<StyledPositionButton
aria-label={position === 'bottom' ? t('moveCompanionWindowToRight') : t('moveCompanionWindowToBottom')}
onClick={() => { updateCompanionWindow({ position: position === 'bottom' ? 'right' : 'bottom' }); }}
>
<MoveIcon />
</StyledPositionButton>
)
}
<StyledCloseButton
sx={{
...(size.width < 370 && {
order: 'unset',
}),
}}
aria-label={t('closeCompanionWindow')}
onClick={onCloseClick}

<StyledToolbar
variant="dense"
className={[ns('companion-window-header'), size.width < 370 ? 'test' : null].join(' ')}
disableGutters
>
<StyledTitle variant="h3">{title}</StyledTitle>
{
position === 'left'
? updateCompanionWindow
&& (
<MiradorMenuButton
aria-label={t('openInCompanionWindow')}
onClick={() => { updateCompanionWindow({ position: 'right' }); }}
>
<CloseIcon />
</StyledCloseButton>
</>
<OpenInNewIcon style={openInNewStyle} />
</MiradorMenuButton>
)
: (
<>
{
updateCompanionWindow && (
<StyledPositionButton
aria-label={position === 'bottom' ? t('moveCompanionWindowToRight') : t('moveCompanionWindowToBottom')}
onClick={() => { updateCompanionWindow({ position: position === 'bottom' ? 'right' : 'bottom' }); }}
>
<MoveIcon />
</StyledPositionButton>
)
}
<StyledCloseButton
sx={{
...(size.width < 370 && {
order: 'unset',
}),
}}
aria-label={t('closeCompanionWindow')}
onClick={onCloseClick}
>
<CloseIcon />
</StyledCloseButton>
</>
)
}
{
titleControls && (
<StyledTitleControls
ownerState={{ position }}
sx={{
order: isBottom || size.width < 370 ? 'unset' : 1000,
}}
className={ns('companion-window-title-controls')}
>
{titleControls}
</StyledTitleControls>
)
}
{
titleControls && (
<StyledTitleControls
ownerState={{ position }}
sx={{
order: isBottom || size.width < 370 ? 'unset' : 1000,
}}
className={ns('companion-window-title-controls')}
>
{titleControls}
</StyledTitleControls>
)
}
</StyledToolbar>
<Contents
className={ns('scrollto-scrollable')}
elevation={0}
>
{childrenWithAdditionalProps}
</Contents>
</StyledRnd>
}
</StyledToolbar>
<Contents
className={ns('scrollto-scrollable')}
elevation={0}
>
{childrenWithAdditionalProps}
</Contents>
</StyledRnd>
</LocaleContext.Provider>
</Root>
);
});
Expand All @@ -193,6 +199,7 @@ CompanionWindow.propTypes = {
defaultSidebarPanelHeight: PropTypes.number,
defaultSidebarPanelWidth: PropTypes.number,
direction: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
isDisplayed: PropTypes.bool,
onCloseClick: PropTypes.func,
paperClassName: PropTypes.string,
Expand Down
28 changes: 28 additions & 0 deletions src/components/IIIFResourceLabel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useContext } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import {
getLocale,
} from '../state/selectors';
import LocaleContext from '../contexts/LocaleContext';

/**
* Render the contextually appropriate label for the resource
*/
export function IIIFResourceLabel({ fallback, resource }) {
const contextLocale = useContext(LocaleContext);
const fallbackLocale = useSelector(state => getLocale(state, {}));

if (!resource) return fallback;

const label = resource.getLabel();

if (!label) return fallback;

return label.getValue(contextLocale || fallbackLocale || '') ?? (fallback || resource.id);
}

IIIFResourceLabel.propTypes = {
fallback: PropTypes.string,
resource: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
Loading

0 comments on commit 40f05d2

Please sign in to comment.