Skip to content

Commit 40f05d2

Browse files
authored
Merge pull request #4054 from ProjectMirador/manifest-getValue-locale2
Refactor manifesto initialization to push property localization down
2 parents 3930da8 + d947941 commit 40f05d2

17 files changed

+200
-197
lines changed

__tests__/src/components/GalleryViewThumbnail.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ describe('GalleryView', () => {
7373
describe('on-demand annotation fetching', () => {
7474
const canvas = {
7575
getHeight: () => 50,
76+
getLabel: () => ({ getValue: () => 'label' }),
7677
getServices: vi.fn(),
7778
getThumbnail: vi.fn(),
7879
getType: vi.fn(),

__tests__/src/components/WindowSideBarCanvasPanel.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ function createWrapper(props) {
1313
let sequences;
1414

1515
if (props.multipleSequences) {
16-
sequences = [{ id: 'a', label: 'seq1' },
17-
{ id: 'b', label: 'seq2' }];
16+
sequences = [{ getLabel: () => ({ getValue: () => undefined }), id: 'a', label: 'seq1' },
17+
{ getLabel: () => ({ getValue: () => undefined }), id: 'b', label: 'seq2' }];
1818
} else {
1919
sequences = Utils.parseManifest(manifestJson).getSequences();
2020
}

__tests__/src/selectors/manifests.test.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,6 @@ describe('getManifestoInstance', () => {
5959
const received = getManifestoInstance(state, { manifestId: 'x' });
6060
expect(received.id).toEqual('http://iiif.io/api/presentation/2.1/example/fixtures/19/manifest.json');
6161
});
62-
it('is cached based off of input props', () => {
63-
const state = { manifests: { x: { json: manifestFixture019 } } };
64-
const received = getManifestoInstance(state, { manifestId: 'x' });
65-
expect(getManifestoInstance(state, { manifestId: 'x' })).toBe(received);
66-
expect(getManifestoInstance(state, { manifestId: 'x', windowId: 'y' })).not.toBe(received);
67-
});
6862
});
6963

7064
describe('getManifestLogo()', () => {

src/components/AppProviders.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { CacheProvider } from '@emotion/react';
1414
import createCache from '@emotion/cache';
1515
import createI18nInstance from '../i18n';
1616
import FullScreenContext from '../contexts/FullScreenContext';
17+
import LocaleContext from '../contexts/LocaleContext';
1718

1819
/**
1920
* Allow applications to opt-out of (or provide their own) drag and drop context
@@ -119,15 +120,17 @@ export function AppProviders({
119120
return (
120121
<FullScreenShim>
121122
<StoreAwareI18nextProvider language={language} translations={translations}>
122-
<StyledEngineProvider injectFirst>
123-
<CacheProvider value={theme.direction === 'rtl' ? cacheRtl : cacheDefault}>
124-
<ThemeProvider theme={createTheme((theme))}>
125-
<MaybeDndProvider dndManager={dndManager}>
126-
{children}
127-
</MaybeDndProvider>
128-
</ThemeProvider>
129-
</CacheProvider>
130-
</StyledEngineProvider>
123+
<LocaleContext.Provider value={language}>
124+
<StyledEngineProvider injectFirst>
125+
<CacheProvider value={theme.direction === 'rtl' ? cacheRtl : cacheDefault}>
126+
<ThemeProvider theme={createTheme((theme))}>
127+
<MaybeDndProvider dndManager={dndManager}>
128+
{children}
129+
</MaybeDndProvider>
130+
</ThemeProvider>
131+
</CacheProvider>
132+
</StyledEngineProvider>
133+
</LocaleContext.Provider>
131134
</StoreAwareI18nextProvider>
132135
</FullScreenShim>
133136
);

src/components/CanvasLayers.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next';
1717
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
1818
import MiradorMenuButton from '../containers/MiradorMenuButton';
1919
import IIIFThumbnail from '../containers/IIIFThumbnail';
20+
import { IIIFResourceLabel } from './IIIFResourceLabel';
2021

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

43-
/** */
44-
function getUseableLabel(resource, index) {
45-
return (resource
46-
&& resource.getLabel
47-
&& resource.getLabel().length > 0)
48-
? resource.getLabel().getValue()
49-
: String(index + 1);
50-
}
51-
5244
/** @private */
5345
function Layer({
5446
resource, layerMetadata = {}, index, handleOpacityChange, setLayerVisibility, moveToTop,
@@ -78,7 +70,7 @@ function Layer({
7870
component="div"
7971
variant="body1"
8072
>
81-
{getUseableLabel(resource, index)}
73+
<IIIFResourceLabel resource={resource} fallback={index + 1} />
8274
<div>
8375
<MiradorMenuButton aria-label={t(layer.visibility ? 'layer_hide' : 'layer_show')} edge="start" size="small" onClick={() => { setLayerVisibility(resource.id, !layer.visibility); }}>
8476
{ layer.visibility ? <VisibilityIcon /> : <VisibilityOffIcon /> }

src/components/CollectionDialog.js

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import CollapsibleSection from '../containers/CollapsibleSection';
2121
import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
2222
import ManifestInfo from '../containers/ManifestInfo';
2323
import WorkspaceContext from '../contexts/WorkspaceContext';
24+
import { IIIFResourceLabel } from './IIIFResourceLabel';
2425

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

41-
/** */
42-
function getUseableLabel(resource, index) {
43-
return (resource
44-
&& resource.getLabel
45-
&& resource.getLabel().length > 0)
46-
? resource.getLabel().getValue()
47-
: String(index + 1);
48-
}
49-
5042
/** */
5143
const Placeholder = ({ onClose, container }) => (
5244
<Dialog
@@ -149,7 +141,7 @@ export function CollectionDialog({
149141
{ t(isMultipart ? 'multipartCollection' : 'collection') }
150142
</Typography>
151143
<Typography component="div" variant="h3">
152-
{getUseableLabel(manifest)}
144+
<IIIFResourceLabel resource={manifest} />
153145
</Typography>
154146
</DialogTitle>
155147
<StyledScrollIndicatedDialogContent>
@@ -158,7 +150,7 @@ export function CollectionDialog({
158150
startIcon={<ArrowBackIcon />}
159151
onClick={() => goToPreviousCollection()}
160152
>
161-
{getUseableLabel(collection)}
153+
<IIIFResourceLabel resource={collection} />
162154
</Button>
163155
)}
164156

@@ -204,7 +196,7 @@ export function CollectionDialog({
204196
onClick={() => { selectCollection(c); }}
205197
variant="multiline"
206198
>
207-
{getUseableLabel(c)}
199+
<IIIFResourceLabel resource={c} />
208200
</MenuItem>
209201
))
210202
}
@@ -219,7 +211,7 @@ export function CollectionDialog({
219211
onClick={() => { selectManifest(m); }}
220212
variant="multiline"
221213
>
222-
{getUseableLabel(m)}
214+
<IIIFResourceLabel resource={m} />
223215
</MenuItem>
224216
))
225217
}

src/components/CompanionWindow.js

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable react/require-default-props */
22
import { Children, cloneElement, forwardRef } from 'react';
3+
import { useSelector } from 'react-redux';
34
import PropTypes from 'prop-types';
45
import { styled } from '@mui/material/styles';
56
import CloseIcon from '@mui/icons-material/CloseSharp';
@@ -14,6 +15,8 @@ import { useElementSize } from '@custom-react-hooks/use-element-size';
1415
import mergeRefs from 'merge-refs';
1516
import MiradorMenuButton from '../containers/MiradorMenuButton';
1617
import ns from '../config/css-ns';
18+
import LocaleContext from '../contexts/LocaleContext';
19+
import { getCompanionWindowLocale } from '../state/selectors/companionWindows';
1720

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

3943
/** */
4044
const openInNewStyle = direction === 'rtl' ? { transform: 'scale(-1, 1)' } : {};
@@ -105,83 +109,85 @@ export const CompanionWindow = forwardRef((props, innerRef) => {
105109
component="aside"
106110
aria-label={ariaLabel || title}
107111
>
108-
<StyledRnd
109-
style={{ display: 'inherit', position: 'inherit' }}
110-
ownerState={props}
111-
default={{
112-
height: isBottom ? defaultSidebarPanelHeight : '100%',
113-
width: isBottom ? 'auto' : defaultSidebarPanelWidth,
114-
}}
115-
disableDragging
116-
enableResizing={resizeHandles}
117-
minHeight={50}
118-
minWidth={position === 'left' ? 235 : 100}
119-
>
120-
121-
<StyledToolbar
122-
variant="dense"
123-
className={[ns('companion-window-header'), size.width < 370 ? 'test' : null].join(' ')}
124-
disableGutters
112+
<LocaleContext.Provider value={locale}>
113+
<StyledRnd
114+
style={{ display: 'inherit', position: 'inherit' }}
115+
ownerState={props}
116+
default={{
117+
height: isBottom ? defaultSidebarPanelHeight : '100%',
118+
width: isBottom ? 'auto' : defaultSidebarPanelWidth,
119+
}}
120+
disableDragging
121+
enableResizing={resizeHandles}
122+
minHeight={50}
123+
minWidth={position === 'left' ? 235 : 100}
125124
>
126-
<StyledTitle variant="h3">{title}</StyledTitle>
127-
{
128-
position === 'left'
129-
? updateCompanionWindow
130-
&& (
131-
<MiradorMenuButton
132-
aria-label={t('openInCompanionWindow')}
133-
onClick={() => { updateCompanionWindow({ position: 'right' }); }}
134-
>
135-
<OpenInNewIcon style={openInNewStyle} />
136-
</MiradorMenuButton>
137-
)
138-
: (
139-
<>
140-
{
141-
updateCompanionWindow && (
142-
<StyledPositionButton
143-
aria-label={position === 'bottom' ? t('moveCompanionWindowToRight') : t('moveCompanionWindowToBottom')}
144-
onClick={() => { updateCompanionWindow({ position: position === 'bottom' ? 'right' : 'bottom' }); }}
145-
>
146-
<MoveIcon />
147-
</StyledPositionButton>
148-
)
149-
}
150-
<StyledCloseButton
151-
sx={{
152-
...(size.width < 370 && {
153-
order: 'unset',
154-
}),
155-
}}
156-
aria-label={t('closeCompanionWindow')}
157-
onClick={onCloseClick}
125+
126+
<StyledToolbar
127+
variant="dense"
128+
className={[ns('companion-window-header'), size.width < 370 ? 'test' : null].join(' ')}
129+
disableGutters
130+
>
131+
<StyledTitle variant="h3">{title}</StyledTitle>
132+
{
133+
position === 'left'
134+
? updateCompanionWindow
135+
&& (
136+
<MiradorMenuButton
137+
aria-label={t('openInCompanionWindow')}
138+
onClick={() => { updateCompanionWindow({ position: 'right' }); }}
158139
>
159-
<CloseIcon />
160-
</StyledCloseButton>
161-
</>
140+
<OpenInNewIcon style={openInNewStyle} />
141+
</MiradorMenuButton>
142+
)
143+
: (
144+
<>
145+
{
146+
updateCompanionWindow && (
147+
<StyledPositionButton
148+
aria-label={position === 'bottom' ? t('moveCompanionWindowToRight') : t('moveCompanionWindowToBottom')}
149+
onClick={() => { updateCompanionWindow({ position: position === 'bottom' ? 'right' : 'bottom' }); }}
150+
>
151+
<MoveIcon />
152+
</StyledPositionButton>
153+
)
154+
}
155+
<StyledCloseButton
156+
sx={{
157+
...(size.width < 370 && {
158+
order: 'unset',
159+
}),
160+
}}
161+
aria-label={t('closeCompanionWindow')}
162+
onClick={onCloseClick}
163+
>
164+
<CloseIcon />
165+
</StyledCloseButton>
166+
</>
167+
)
168+
}
169+
{
170+
titleControls && (
171+
<StyledTitleControls
172+
ownerState={{ position }}
173+
sx={{
174+
order: isBottom || size.width < 370 ? 'unset' : 1000,
175+
}}
176+
className={ns('companion-window-title-controls')}
177+
>
178+
{titleControls}
179+
</StyledTitleControls>
162180
)
163-
}
164-
{
165-
titleControls && (
166-
<StyledTitleControls
167-
ownerState={{ position }}
168-
sx={{
169-
order: isBottom || size.width < 370 ? 'unset' : 1000,
170-
}}
171-
className={ns('companion-window-title-controls')}
172-
>
173-
{titleControls}
174-
</StyledTitleControls>
175-
)
176-
}
177-
</StyledToolbar>
178-
<Contents
179-
className={ns('scrollto-scrollable')}
180-
elevation={0}
181-
>
182-
{childrenWithAdditionalProps}
183-
</Contents>
184-
</StyledRnd>
181+
}
182+
</StyledToolbar>
183+
<Contents
184+
className={ns('scrollto-scrollable')}
185+
elevation={0}
186+
>
187+
{childrenWithAdditionalProps}
188+
</Contents>
189+
</StyledRnd>
190+
</LocaleContext.Provider>
185191
</Root>
186192
);
187193
});
@@ -193,6 +199,7 @@ CompanionWindow.propTypes = {
193199
defaultSidebarPanelHeight: PropTypes.number,
194200
defaultSidebarPanelWidth: PropTypes.number,
195201
direction: PropTypes.string.isRequired,
202+
id: PropTypes.string.isRequired,
196203
isDisplayed: PropTypes.bool,
197204
onCloseClick: PropTypes.func,
198205
paperClassName: PropTypes.string,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useContext } from 'react';
2+
import { useSelector } from 'react-redux';
3+
import PropTypes from 'prop-types';
4+
import {
5+
getLocale,
6+
} from '../state/selectors';
7+
import LocaleContext from '../contexts/LocaleContext';
8+
9+
/**
10+
* Render the contextually appropriate label for the resource
11+
*/
12+
export function IIIFResourceLabel({ fallback, resource }) {
13+
const contextLocale = useContext(LocaleContext);
14+
const fallbackLocale = useSelector(state => getLocale(state, {}));
15+
16+
if (!resource) return fallback;
17+
18+
const label = resource.getLabel();
19+
20+
if (!label) return fallback;
21+
22+
return label.getValue(contextLocale || fallbackLocale || '') ?? (fallback || resource.id);
23+
}
24+
25+
IIIFResourceLabel.propTypes = {
26+
fallback: PropTypes.string,
27+
resource: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
28+
};

0 commit comments

Comments
 (0)