Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: don't store media on item page when IIIF #2446

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/portal/src/components/iiif/IIIFMiradorViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@

*watchMiradorSetCanvas({ canvasId }) {
this.memoiseImageToCanvasMap();
this.postUpdatedDownloadLinkMessage(canvasId);
this.emitSelectEvent(canvasId);
yield;
},

Expand Down Expand Up @@ -615,15 +615,15 @@
}
},

postUpdatedDownloadLinkMessage(pageId) {
emitSelectEvent(pageId) {
if (!this.manifest) {
return;
}

const link = this.findDownloadLinkForPage(pageId);

if (link) {
window.parent.postMessage({ event: 'updateDownloadLink', id: link }, window.location.origin);
this.$emit('select', { about: link });
}
},

Expand Down
34 changes: 7 additions & 27 deletions packages/portal/src/components/item/ItemHero.vue
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,15 @@
},
data() {
return {
selectedMediaItem: null,
selectedCanvas: null
selectedMedia: this.media?.[0] || {}
};
},
computed: {
downloadEnabled() {
return this.rightsStatement && !this.rightsStatement.includes('/InC/') && !this.selectedMedia.forEdmIsShownAt && !this.selectedMedia.isOEmbed && !!this.downloadUrl;
},
downloadUrl() {
const url = (this.selectedCanvas || this.selectedMedia).about;
const url = this.selectedMedia.about;
return this.downloadViaProxy(url) ? this.$apis.record.mediaProxyUrl(url, this.identifier) : url;
},
rightsStatementIsUrl() {
Expand Down Expand Up @@ -179,18 +181,6 @@

return query.join(' ');
},
selectedMedia: {
get() {
return this.selectedMediaItem || this.media[0] || {};
},
set(about) {
this.selectedCanvas = null;
this.selectedMediaItem = this.media.find((item) => item.about === about) || {};
}
},
downloadEnabled() {
return this.rightsStatement && !this.rightsStatement.includes('/InC/') && !this.selectedMedia.forEdmIsShownAt && !this.selectedMedia.isOEmbed && !!this.downloadUrl;
},
showPins() {
return this.userIsEntitiesEditor && this.userIsSetsEditor && this.entities.length > 0;
},
Expand All @@ -204,25 +194,15 @@
return this.$features.transcribathonCta && this.linkForContributingAnnotation && TRANSCRIBATHON_URL_ROOT.test(this.linkForContributingAnnotation);
}
},
mounted() {
window.addEventListener('message', msg => {
if (msg.origin !== window.location.origin) {
return;
}
if (msg.data.event === 'updateDownloadLink') {
this.selectedCanvas = { about: msg.data.id };
}
});
},
methods: {
// Ensure we only proxy web resource media, preventing proxying of
// arbitrary other resources such as images linked from (non-Europeana-hosted)
// IIIF manifests.
downloadViaProxy(url) {
return this.allMediaUris.some(uri => uri === url);
},
selectMedia(about) {
this.selectedMedia = about;
selectMedia(resource) {
this.selectedMedia = resource;
}
}
};
Expand Down
6 changes: 4 additions & 2 deletions packages/portal/src/components/item/ItemMediaLegacy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@
},

methods: {
selectMedia(id) {
this.$emit('select', id);
selectMedia(resource) {
this.$nextTick(() => {
this.$emit('select', resource);
});
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
this.page = Number(this.$route.query.page) || 1;
this.activeAnnotation = null;
this.$nextTick(() => {
this.$emit('select', this.resource?.about);
this.$emit('select', this.resource);
});
},

Expand Down
10 changes: 5 additions & 5 deletions packages/portal/src/components/item/ItemMediaSwiper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<span class="swiper-pagination d-inline-flex" />
</div>
<div
ref="swiperThubmnails"
ref="swiperThumbnails"
class="swiper-thumbnails d-flex flex-row flex-lg-column"
>
<ItemMediaSwiperThumbnail
Expand Down Expand Up @@ -138,19 +138,19 @@
methods: {
onSlideChange() {
this.updateThumbnailScroll();
this.$emit('select', this.displayableMedia[this.swiper.activeIndex].about);
this.$emit('select', this.displayableMedia[this.swiper.activeIndex]);
},
updateSwiper() {
this.swiper.update();
},
updateThumbnailScroll() {
// TODO: fix these values to use CSS values, not be hardcoded
if (window.innerWidth <= 767) {
this.$refs.swiperThubmnails?.scroll(16 + (this.swiper.activeIndex * 96), 0);
this.$refs.swiperThumbnails?.scroll(16 + (this.swiper.activeIndex * 96), 0);
} else if (window.innerWidth <= 991) {
this.$refs.swiperThubmnails?.scroll(16 + (this.swiper.activeIndex * 192), 0);
this.$refs.swiperThumbnails?.scroll(16 + (this.swiper.activeIndex * 192), 0);
} else {
this.$refs.swiperThubmnails?.scroll(0, this.swiper.activeIndex * 138);
this.$refs.swiperThumbnails?.scroll(0, this.swiper.activeIndex * 138);
}
},
swiperOnAfterInit() {
Expand Down
18 changes: 16 additions & 2 deletions packages/portal/src/pages/item/_.vue
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
isShownAt: null,
media: [],
metadata: {},
ogImage: null,
relatedCollections: [],
showItemLanguageSelector: true,
type: null,
Expand All @@ -212,7 +213,7 @@
title: this.titlesInCurrentLanguage[0]?.value || this.$t('record.record'),
description: isEmpty(this.descriptionInCurrentLanguage) ? '' : (this.descriptionInCurrentLanguage.values[0] || ''),
ogType: 'article',
ogImage: this.webResources[0]?.thumbnails(this.$nuxt.context)?.large
ogImage: this.ogImage
};
},
keywords() {
Expand Down Expand Up @@ -375,10 +376,23 @@

const item = new Item(edm);

// TODO: ideally, wouldn't store these as can be a large list if many WRs,
// but relied on by ItemHero to know whether to proxy download urls or not.
// could we deduce that from whether iiif is in use or not, and if
// so, whether a europeana manifest?
// - not iiif: proxy
// - iiif, europeana: proxy
// - iiif, institution: don't proxy
this.allMediaUris = item.providerAggregation.displayableWebResources.map((wr) => wr.about);
this.iiifPresentationManifest = item.iiifPresentationManifest;
this.isShownAt = item.providerAggregation.edmIsShownAt;
this.media = item.providerAggregation.displayableWebResources;

this.ogImage = new WebResource(item.providerAggregation.displayableWebResources[0], this.identifier)?.thumbnails(this.$nuxt.context)?.large;

// don't store the web resources when using iiif as the manifest will be used
if (!this.iiifPresentationManifest) {
this.media = item.providerAggregation.displayableWebResources;
}

this.entities = this.extractEntities(edm);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@ describe('components/iiif/IIIFMiradorViewer.vue', () => {
expect(wrapper.vm.memoiseImageToCanvasMap.called).toBe(true);
});

it('calls postUpdatedDownloadLinkMessage with canvasId', () => {
it('calls emitSelectEvent with canvasId', () => {
const manifest = {
'@context': 'http://iiif.io/api/presentation/3/context.json'
};
const wrapper = factory({ data: { manifest } });
sinon.spy(wrapper.vm, 'postUpdatedDownloadLinkMessage');
sinon.spy(wrapper.vm, 'emitSelectEvent');

wrapper.vm.watchMiradorSetCanvas({ canvasId: 'https://example.org/canvas' }).next();

expect(wrapper.vm.postUpdatedDownloadLinkMessage.calledWith('https://example.org/canvas')).toBe(true);
expect(wrapper.vm.emitSelectEvent.calledWith('https://example.org/canvas')).toBe(true);
});
});

Expand Down Expand Up @@ -684,7 +684,7 @@ describe('components/iiif/IIIFMiradorViewer.vue', () => {
});
});

describe('postUpdatedDownloadLinkMessage', () => {
describe('emitSelectEvent', () => {
const pageId = 'https://iiif.europeana.eu/presentation/123/abc/canvas/p1';
const imageUrl = 'https://iiif.europeana.eu/image/123/abc/default.jpg';

Expand All @@ -696,17 +696,10 @@ describe('components/iiif/IIIFMiradorViewer.vue', () => {

it('posts image URL from sequences canvas matching page ID', () => {
const wrapper = factory({ data: { manifest } });
sinon.spy(window.parent, 'postMessage');

wrapper.vm.postUpdatedDownloadLinkMessage(pageId);
wrapper.vm.emitSelectEvent(pageId);

expect(window.parent.postMessage.calledWith(
{
event: 'updateDownloadLink',
id: imageUrl
},
'http://localhost'
)).toBe(true);
expect(wrapper.emitted('select')).toEqual([[{ about: imageUrl }]]);
});
});

Expand All @@ -716,19 +709,12 @@ describe('components/iiif/IIIFMiradorViewer.vue', () => {
items: [{ id: pageId, items: [{ items: [{ body: { id: imageUrl } }] }] }]
};

it('posts image URL from canvas item matching page ID', () => {
it('emits select event with image URL from canvas item matching page ID', () => {
const wrapper = factory({ data: { manifest } });
sinon.spy(window.parent, 'postMessage');

wrapper.vm.postUpdatedDownloadLinkMessage(pageId);
wrapper.vm.emitSelectEvent(pageId);

expect(window.parent.postMessage.calledWith(
{
event: 'updateDownloadLink',
id: imageUrl
},
'http://localhost'
)).toBe(true);
expect(wrapper.emitted('select')).toEqual([[{ about: imageUrl }]]);
});
});
});
Expand Down
35 changes: 13 additions & 22 deletions packages/portal/tests/unit/components/item/ItemHero.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,15 @@ describe('components/item/ItemHero', () => {
describe('when a new item is selected', () => {
it('updates the identifier', () => {
const wrapper = factory({ propsData: { media, identifier } });
wrapper.vm.selectMedia(media[1].about);
wrapper.vm.selectMedia(media[1]);
expect(wrapper.vm.selectedMedia.about).toBe(media[1].about);
});

it('updates the rights statement', () => {
const wrapper = factory({ propsData: { media, identifier } });
wrapper.vm.selectMedia(media[1].about);
wrapper.vm.selectMedia(media[1]);
expect(wrapper.vm.selectedMedia.webResourceEdmRights.def[0]).toBe(media[1].webResourceEdmRights.def[0]);
});
it('unsets any selected IIIF canvas', async() => {
const wrapper = factory({ propsData: { media, identifier } });
await wrapper.setData({ selectedCanvas: { about: 'http://www.example.org/canvas' } });
wrapper.vm.selectMedia(media[1].about);
expect(wrapper.vm.selectedCanvas === null).toBe(true);
});
});
});

Expand All @@ -141,29 +136,25 @@ describe('components/item/ItemHero', () => {
});

describe('downloadUrl', () => {
// allMediaUris set to existing media plus one iiif canvas
const propsData = { allMediaUris: media.map((media) => media.about).concat('http://www.example.org/canvas'), media, identifier };
const propsData = { allMediaUris: media.map((media) => media.about) };

describe('when the webresource is the isShownBy', () => {
it('uses the proxy', async() => {
const wrapper = factory({ propsData });

await wrapper.setData({ selectedMedia: media[0] });

expect(wrapper.vm.downloadUrl).toBe('proxied - https://europeana1914-1918.s3.amazonaws.com/attachments/119112/10265.119112.original.jpg');
});
});
describe('when the webresource is a newspaper IIIF canvas', () => {
it('uses the proxy', async() => {
const wrapper = factory({ propsData });
await wrapper.setData({ selectedMedia: media[0] });
await wrapper.setData({ selectedCanvas: { about: 'http://www.example.org/canvas' } });
expect(wrapper.vm.downloadUrl).toBe('proxied - http://www.example.org/canvas');
});
});
describe('when the webresource is an unknown IIIF canvas', () => {

describe('when the webresource is an unknown image, e.g. from IIIF', () => {
it('does not use the proxy', async() => {
const wrapper = factory({ propsData });
await wrapper.setData({ selectedMedia: media[0] });
await wrapper.setData({ selectedCanvas: { about: 'http://www.example.org/another-canvas' } });
expect(wrapper.vm.downloadUrl).toBe('http://www.example.org/another-canvas');

await wrapper.setData({ selectedMedia: { about: 'http://www.example.org/other.jpeg' } });

expect(wrapper.vm.downloadUrl).toBe('http://www.example.org/other.jpeg');
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ describe('components/item/ItemMediaSwiper', () => {
});
});
describe('onSlideChange()', () => {
it('emits a `select` event with the item identifier', () => {
it('emits a `select` event with the item', () => {
const wrapper = factory({ europeanaIdentifier, displayableMedia });

wrapper.vm.$refs.swiperThubmnails.scroll = sinon.stub();
wrapper.vm.$refs.swiperThumbnails.scroll = sinon.stub();

wrapper.vm.swiper.activeIndex = 1;
wrapper.vm.onSlideChange();

expect(wrapper.emitted('select')).toEqual([[displayableMedia[1].about]]);
expect(wrapper.emitted('select')).toEqual([[displayableMedia[1]]]);
});
});
describe('updateSwiper()', () => {
Expand All @@ -88,12 +88,12 @@ describe('components/item/ItemMediaSwiper', () => {
it('calls `scroll` event on the thumbnail wrapper', () => {
const wrapper = factory({ europeanaIdentifier, displayableMedia });

wrapper.vm.$refs.swiperThubmnails.scroll = sinon.spy();
wrapper.vm.$refs.swiperThumbnails.scroll = sinon.spy();

wrapper.vm.swiper.activeIndex = 1;
wrapper.vm.updateThumbnailScroll();

expect(wrapper.vm.$refs.swiperThubmnails.scroll.called).toEqual(true);
expect(wrapper.vm.$refs.swiperThumbnails.scroll.called).toEqual(true);
});
});
describe('singleMediaResource', () => {
Expand Down
Loading
Loading