Skip to content

Commit d456495

Browse files
authored
Load UV 4 directly, not in iframe (#75)
1 parent 5a46157 commit d456495

File tree

7 files changed

+212
-90
lines changed

7 files changed

+212
-90
lines changed

cypress/e2e/collection.spec.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
describe('A IIIF Collection', () => {
2-
const URL_PARAMETERS = '#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fcollections%2Fark%253A%252F21198%252Fz11c574k';
2+
const URL_PARAMETERS =
3+
'#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fcollections%2Fark%253A%252F21198%252Fz11c574k'
34

4-
it('loads Universal Viewer in an iframe', () => {
5-
cy.visit('/' + URL_PARAMETERS)
6-
7-
// UV loads inside an iframe
8-
cy.frameLoaded("#universalviewer-iframe", {
9-
url: '/uv.html' + URL_PARAMETERS,
10-
});
11-
})
12-
13-
14-
it('loads in Universal Viewer!', () => {
15-
cy.visit('/uv.html' + URL_PARAMETERS)
16-
17-
})
5+
it('loads in Universal Viewer!', () => {
6+
cy.visit('/' + URL_PARAMETERS)
187
})
19-
8+
})

cypress/e2e/image.spec.js

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,29 @@
11
describe('A simple image', () => {
2-
const URL_PARAMETERS = '#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fark%253A%252F21198%252Fzz00090p17%2Fmanifest'
3-
4-
it('loads Universal Viewer in an iframe', () => {
5-
cy.visit('/' + URL_PARAMETERS)
6-
7-
// UV loads inside an iframe
8-
cy.frameLoaded("#universalviewer-iframe", {
9-
url: '/uv.html' + URL_PARAMETERS,
10-
});
11-
})
12-
2+
const URL_PARAMETERS =
3+
'#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fark%253A%252F21198%252Fzz00090p17%2Fmanifest'
134

145
it('loads in Universal Viewer!', () => {
15-
cy.visit('/uv.html' + URL_PARAMETERS)
6+
cy.visit('/' + URL_PARAMETERS)
167

178
// Shows title
18-
cy.contains('.title', "1985 - The California Poppy").should("exist").should("be.visible")
9+
cy.contains('.title', '1985 - The California Poppy').should('exist').should('be.visible')
1910

2011
// Settings Button
21-
cy.get("button.settings").should("exist").should("be.visible")
12+
cy.get('button.settings').should('exist').should('be.visible')
2213

2314
// left panel is disabled
24-
cy.get(".leftPanel").should("exist").should("not.be.visible")
15+
cy.get('.leftPanel').should('exist').should('not.be.visible')
2516

2617
// "Print" is disabled
27-
cy.contains("Print").should("exist").should("not.be.visible")
18+
cy.contains('Print').should('exist').should('not.be.visible')
2819

2920
// "Share" is disabled
30-
cy.contains("Share").should("exist").should("not.be.visible")
21+
cy.contains('Share').should('exist').should('not.be.visible')
3122

3223
// Enter / exit fullcreen view
33-
cy.contains("Full Screen").should("exist").should("be.visible")
24+
cy.contains('Full Screen').should('exist').should('be.visible')
3425

3526
// Download button enabled
36-
cy.contains('Download').should("exist").should("be.visible")
27+
cy.contains('Download').should('exist').should('be.visible')
3728
})
3829
})

cypress/e2e/manuscript.spec.js

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,68 @@
11
describe('A manuscript', () => {
2-
const URL_PARAMETERS = '#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fark%253A%252F21198%252Fzz0009gx6g%2Fmanifest'
3-
4-
it('loads Universal Viewer in an iframe', () => {
5-
cy.visit('/' + URL_PARAMETERS)
6-
7-
// UV loads inside an iframe
8-
cy.frameLoaded("#universalviewer-iframe", {
9-
url: '/uv.html' + URL_PARAMETERS,
10-
});
11-
})
2+
const URL_PARAMETERS =
3+
'#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fark%253A%252F21198%252Fzz0009gx6g%2Fmanifest'
124

135
it('loads in Universal Viewer!', () => {
14-
cy.visit('/uv.html' + URL_PARAMETERS)
6+
cy.visit('/' + URL_PARAMETERS)
157

168
// Shows title
17-
cy.contains('.title', "Manuscript No. 1: Gladzor Gospels").should("exist").should("be.visible")
9+
cy.contains('.title', 'Manuscript No. 1: Gladzor Gospels').should('exist').should('be.visible')
1810

1911
// Settings Button
20-
cy.get("button.settings").should("exist").should("be.visible")
12+
cy.get('button.settings').should('exist').should('be.visible')
2113

2214
// left panel
2315
// is visible, first page selected
24-
cy.get(".leftPanel").should("exist").should("be.visible")
25-
.get("#thumb-0 > .thumb").should("have.class", "selected")
16+
cy.get('.leftPanel').should('exist').should('be.visible')
17+
18+
cy.get('#thumb-0 > .thumb').should('have.class', 'selected')
2619
// navigate to 3rd page by clicking thumbnail
27-
cy.get("#thumb-2 > .thumb").should("not.have.class", "selected")
28-
.get("#thumb-2 img").click()
29-
.get("#thumb-0 > .thumb").should("not.have.class", "selected")
30-
.get("#thumb-1 > .thumb").should("have.class", "selected")
31-
.get("#thumb-2 > .thumb").should("have.class", "selected")
20+
cy.get('#thumb-2 > .thumb').should('not.have.class', 'selected')
21+
22+
cy.get('#thumb-2 img').click()
23+
24+
cy.get('#thumb-0 > .thumb').should('not.have.class', 'selected')
25+
26+
cy.get('#thumb-1 > .thumb').should('have.class', 'selected')
27+
28+
cy.get('#thumb-2 > .thumb').should('have.class', 'selected')
3229
// navigate to 4th page by clicking thumbnail
33-
cy.get("#thumb-3 > .thumb").should("not.have.class", "selected")
34-
.contains("[Gladzor Gospels: page 2]").click()
35-
.get("#thumb-2 > .thumb").should("not.have.class", "selected")
36-
.get("#thumb-3 > .thumb").should("have.class", "selected")
37-
.get("#thumb-4 > .thumb").should("have.class", "selected")
30+
cy.get('#thumb-3 > .thumb')
31+
.should('not.have.class', 'selected')
32+
.contains('[Gladzor Gospels: page 2]')
33+
.click()
34+
35+
cy.get('#thumb-2 > .thumb').should('not.have.class', 'selected')
36+
37+
cy.get('#thumb-3 > .thumb').should('have.class', 'selected')
38+
39+
cy.get('#thumb-4 > .thumb').should('have.class', 'selected')
3840
// collapse left panel
39-
cy.get(".expandFullButton").should("exist").should("not.be.visible")
40-
.get(".collapseButton").should("exist").should("be.visible").click()
41-
.get(".leftPanel > .main").should("exist").should("not.be.visible")
41+
cy.get('.expandFullButton').should('exist').should('not.be.visible')
42+
43+
cy.get('.collapseButton').should('exist').should('be.visible').click()
44+
45+
cy.get('.leftPanel > .main').should('exist').should('not.be.visible')
4246

4347
// "Print" is disabled
44-
cy.contains("Print").should("exist").should("not.be.visible")
48+
cy.contains('Print').should('exist').should('not.be.visible')
4549

4650
// "Share" is disabled
47-
cy.contains("Share").should("exist").should("not.be.visible")
51+
cy.contains('Share').should('exist').should('not.be.visible')
4852

4953
// Fullscreen button
50-
cy.contains("Full Screen").should("exist").should("be.visible")
54+
cy.contains('Full Screen').should('exist').should('be.visible')
5155

5256
// Download button
53-
cy.contains('Download').should("exist").should("be.visible")
57+
cy.contains('Download').should('exist').should('be.visible')
58+
})
59+
60+
it('allows deep linking by canvas index', () => {
61+
cy.visit('/' + URL_PARAMETERS + '&cv=30')
62+
63+
cy.get('.leftPanel #thumb-29 > .thumb')
64+
.should('exist')
65+
.should('be.visible')
66+
.should('have.class', 'selected')
5467
})
5568
})

cypress/e2e/tree_view.spec.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
describe('A manuscript', () => {
2+
const URL_PARAMETERS =
3+
'#?manifest=https%3A%2F%2Fiiif.library.ucla.edu%2Fcollections%2Fark%253A%252F21198%252Fz14q9t15'
4+
5+
it('loads in Universal Viewer!', () => {
6+
cy.visit('/' + URL_PARAMETERS)
7+
8+
// Shows title
9+
cy.contains('.title', 'No. 01').should('exist').should('be.visible')
10+
11+
// Settings Button
12+
cy.get('button.settings').should('exist').should('be.visible')
13+
14+
// left panel
15+
// is visible, in tree view
16+
cy.get('.leftPanel').should('exist').should('be.visible')
17+
cy.get('.leftPanel .treeView').should('exist').should('be.visible')
18+
cy.get('.leftPanel .treeView').contains('a', 'No. 01').should('have.class', 'selected')
19+
20+
// Choose a different issue from tree view
21+
cy.get('.leftPanel .treeView').contains('a', 'No. 17').click()
22+
cy.contains('.title', 'No. 17').should('exist').should('be.visible')
23+
cy.contains('.title', 'No. 01').should('not.exist')
24+
cy.get('.leftPanel .treeView').contains('a', 'No. 17').should('have.class', 'selected')
25+
26+
// Go to thumbnail view
27+
cy.get('.leftPanel').contains('a', 'Thumbnails').click()
28+
29+
cy.get('#thumb-0 > .thumb').should('have.class', 'selected')
30+
// navigate to 3rd page by clicking thumbnail
31+
cy.get('#thumb-2 > .thumb').should('not.have.class', 'selected')
32+
cy.get('#thumb-2 img').click()
33+
cy.get('#thumb-0 > .thumb')
34+
.should('not.have.class', 'selected')
35+
.get('#thumb-1 > .thumb')
36+
.should('have.class', 'selected')
37+
.get('#thumb-2 > .thumb')
38+
.should('have.class', 'selected')
39+
// navigate to 4th page by clicking thumbnail
40+
cy.get('#thumb-3 > .thumb').should('not.have.class', 'selected').contains('Page 4').click()
41+
cy.get('#thumb-2 > .thumb')
42+
.should('not.have.class', 'selected')
43+
.get('#thumb-3 > .thumb')
44+
.should('have.class', 'selected')
45+
.get('#thumb-4 > .thumb')
46+
.should('have.class', 'selected')
47+
// collapse left panel
48+
cy.get('.expandFullButton').should('exist').should('not.be.visible')
49+
cy.get('.collapseButton').should('exist').should('be.visible').click()
50+
cy.get('.leftPanel > .main').should('exist').should('not.be.visible')
51+
52+
// "Print" is disabled
53+
cy.contains('Print').should('exist').should('not.be.visible')
54+
55+
// "Share" is disabled
56+
cy.contains('Share').should('exist').should('not.be.visible')
57+
58+
// Fullscreen button
59+
cy.contains('Full Screen').should('exist').should('be.visible')
60+
61+
// Download button
62+
cy.contains('Download').should('exist').should('be.visible')
63+
})
64+
})

src/App.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
v-if="iiif_manifest_url && iiif_manifest_url.length > 0"
44
:iiif_manifest_url="iiif_manifest_url"
55
:site="site"
6+
:canvas="canvas"
67
/>
78
</template>
89

910
<script lang="ts">
11+
import { toInteger } from 'lodash'
1012
import DLViewer from './components/DLViewer.vue'
1113
import _isString from 'lodash/isString'
1214
@@ -34,6 +36,9 @@ export default {
3436
}
3537
return iiif_url
3638
},
39+
canvas() {
40+
return toInteger(this.normalized_url.searchParams.get('cv')) || undefined
41+
},
3742
site() {
3843
return this.normalized_url.searchParams.get('site') || undefined
3944
},

src/components/DLViewer.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
<div class="dl-viewer" v-if="iiif_manifest">
33
<mirador-palimpsest v-if="isSinaiPalimpsest" />
44
<MiradorViewer v-else-if="isSinai" />
5-
<UniversalViewer v-else-if="isCollection" />
5+
<UniversalViewer
6+
v-else-if="isCollection"
7+
:iiif_manifest_url="iiif_manifest_url"
8+
:canvas="canvas"
9+
/>
610
<VideoJS v-else-if="isVideo" :iiif_manifest="iiif_manifest" />
711
<UniversalViewer3 v-else-if="isSound" />
812
<ImageTag v-else-if="isImage && !hasIiifService" :iiif_manifest="iiif_manifest" />
9-
<UniversalViewer v-else :isSound="isSound" />
13+
<UniversalViewer v-else :iiif_manifest_url="iiif_manifest_url" :canvas="canvas" />
1014
</div>
1115
</template>
1216

@@ -44,6 +48,10 @@ export default {
4448
type: String,
4549
default: '',
4650
},
51+
canvas: {
52+
type: Number,
53+
default: 0,
54+
},
4755
},
4856
data() {
4957
return {

src/components/UniversalViewer.vue

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,83 @@
1-
<template>
2-
<iframe
3-
class="universalviewer"
4-
:src="iframe_target_url"
5-
id="universalviewer-iframe"
6-
allowfullscreen
7-
frameborder="0"
8-
/>
9-
</template>
1+
<template><div id="uv" class="uv" allowfullscreen frameborder="0" /></template>
102

11-
<script lang="ts">
12-
/* eslint-disable */
3+
<script setup lang="ts">
4+
import { init } from 'universalviewer'
5+
import { onMounted } from 'vue'
6+
import 'universalviewer/dist/esm/index.css'
137
14-
export default {
15-
computed: {
16-
iframe_target_url() {
17-
// console.log("viewer 4")
18-
const fixed_url = new URL(window.location.toString().replace('#?', '?')) // for some reason the URL format we inherited used '#?' to indicate query parameters, but URLSearchParams won't parse this.
19-
console.log(`uv.html#${fixed_url.search}`)
20-
return `uv.html#${fixed_url.search}`
21-
},
8+
const props = defineProps({
9+
iiif_manifest_url: {
10+
type: String,
11+
required: true,
2212
},
23-
}
13+
canvas: {
14+
type: Number,
15+
default: 0,
16+
},
17+
})
18+
19+
onMounted(() => {
20+
const uv_config = {
21+
options: {
22+
rightPanelEnabled: false,
23+
},
24+
modules: {
25+
contentLeftPanel: {
26+
options: {
27+
defaultToTreeEnabled: true,
28+
},
29+
},
30+
headerPanel: {
31+
options: {
32+
settingsButtonEnabled: true,
33+
},
34+
},
35+
footerPanel: {
36+
options: {
37+
downloadEnabled: true,
38+
moreInfoEnabled: false,
39+
printEnabled: false,
40+
shareEnabled: false,
41+
},
42+
content: {
43+
download: 'Download ',
44+
exitFullScreen: 'Exit Full Screen',
45+
fullScreen: 'Full Screen HEYYYYYYY',
46+
},
47+
},
48+
downloadDialogue: {
49+
options: {
50+
confinedImageSize: 200,
51+
currentViewDisabledPercentage: 90,
52+
maxImageWidth: 5000,
53+
optionsExplanatoryTextEnabled: true,
54+
selectionEnabled: false,
55+
},
56+
},
57+
},
58+
}
59+
60+
const uv = init('uv', {
61+
manifest: props.iiif_manifest_url,
62+
canvasIndex: props.canvas,
63+
})
64+
65+
uv.on('configure', function ({ cb }: { cb: (cfg: unknown) => void }) {
66+
// Ensure the configure callback returns a Promise so the
67+
// BaseContentHandler.configure flow handles the value reliably
68+
// (and add a log to confirm the configure handler runs).
69+
// Passing a Promise.wrap/Promise.resolve mirrors the extension
70+
// expectation for async config merges.
71+
// See: BaseContentHandler.configure -> Promise.all([...])
72+
console.log('uv configure handler called with config:', uv_config)
73+
cb(Promise.resolve(uv_config))
74+
})
75+
})
2476
</script>
2577

2678
<!-- Add "scoped" attribute to limit CSS to this component only -->
2779
<style scoped>
28-
.universalviewer {
80+
.uv {
2981
width: 100%;
3082
height: 100%;
3183
}

0 commit comments

Comments
 (0)