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

fix: make prev and next slides not focusable and aria-hidden #2091

Merged
merged 3 commits into from
Jan 5, 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
79 changes: 79 additions & 0 deletions cypress/e2e/a11y.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
describe('A11y tests', function() {
before(function() {
// Init user
cy.createRandomUser().then(user => {
// Upload test files
cy.uploadFile(user, 'image1.jpg', 'image/jpeg')
cy.uploadFile(user, 'image2.jpg', 'image/jpeg')
cy.uploadFile(user, 'video1.mp4', 'video/mp4')

// Visit nextcloud
cy.login(user)
cy.visit('/apps/files')
})
})

after(function() {
cy.logout()
})

it('See files in the list', function() {
cy.getFile('image1.jpg', { timeout: 10000 })
.should('contain', 'image1 .jpg')
cy.getFile('image2.jpg', { timeout: 10000 })
.should('contain', 'image2 .jpg')
cy.getFile('video1.mp4', { timeout: 10000 })
.should('contain', 'video1 .mp4')
})

it('Open the viewer on file click', function() {
cy.openFile('image2.jpg')
cy.get('body > .viewer').should('be.visible')
})

it('Does not see a loading animation', function() {
cy.get('body > .viewer', { timeout: 10000 })
.should('be.visible')
.and('have.class', 'modal-mask')
.and('not.have.class', 'icon-loading')
})

it('See the title on the viewer header', function() {
cy.get('body > .viewer .modal-name').should('contain', 'image2.jpg')
})

it('Should have rendered the previous video and the next image', function() {
// There are buttons to navigate to the previous and next image
cy.get('body > .viewer button.prev').should('be.visible')
cy.get('body > .viewer button.next').should('be.visible')
// The previous and the next image
cy.get('body > .viewer .modal-container img').should('have.length', 2)
// The next video
cy.get('body > .viewer .modal-container video').should('have.length', 1)
})

it('Should make the previous and the next slides hidden for assistive technologies', function() {
// Cypress doesn't respect aria-hidden in should.be.visible
cy.get('body > .viewer .modal-container .viewer__file:not(.viewer__file--active) video')
.parents('[aria-hidden="true"]')
.should('exist')
cy.get('body > .viewer .modal-container .viewer__file:not(.viewer__file--active) video')
.parents('[inert]')
.should('exist')
cy.get('body > .viewer .modal-container img.viewer__file:not(.viewer__file--active)')
.parents('[aria-hidden="true"]')
.should('exist')
cy.get('body > .viewer .modal-container img.viewer__file:not(.viewer__file--active)')
.parents('[inert]')
.should('exist')
})

it('Should make vido controls on the next slide not focusable', function() {
cy.get('body > .viewer .modal-container .viewer__file:not(.viewer__file--active):has(video) button')
.first()
.focus()
cy.get('body > .viewer .modal-container .viewer__file:not(.viewer__file--active):has(video) button')
.first()
.should('not.have.focus')
})
})
4 changes: 2 additions & 2 deletions js/viewer-main.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/viewer-main.js.map

Large diffs are not rendered by default.

128 changes: 71 additions & 57 deletions src/views/Viewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,65 +113,75 @@

<div class="viewer__content" :class="contentClass" @click.self.exact="close">
<!-- COMPARE FILE -->
<component :is="comparisonFile.modal"
v-if="comparisonFile && !comparisonFile.failed && showComparison"
:key="comparisonFile | uniqueKey"
ref="comparison-content"
v-bind="comparisonFile"
:active="true"
:can-swipe="false"
:can-zoom="false"
:editing="false"
:is-full-screen="isFullscreen"
:is-sidebar-shown="isSidebarShown"
:loaded.sync="comparisonFile.loaded"
class="viewer__file viewer__file--active"
@error="comparisonFailed" />
<div v-if="comparisonFile && !comparisonFile.failed && showComparison" class="viewer__file-wrapper">
<component :is="comparisonFile.modal"
:key="comparisonFile | uniqueKey"
ref="comparison-content"
v-bind="comparisonFile"
:active="true"
:can-swipe="false"
:can-zoom="false"
:editing="false"
:is-full-screen="isFullscreen"
:is-sidebar-shown="isSidebarShown"
:loaded.sync="comparisonFile.loaded"
class="viewer__file viewer__file--active"
@error="comparisonFailed" />
</div>

<!-- PREVIOUS -->
<component :is="previousFile.modal"
v-if="previousFile && !previousFile.failed"
<div v-if="previousFile"
:key="previousFile | uniqueKey"
ref="previous-content"
v-bind="previousFile"
:file-list="fileList"
class="viewer__file--hidden viewer__file"
@error="previousFailed" />
<Error v-else-if="previousFile"
class="hidden-visually"
:name="previousFile.basename" />
class="viewer__file-wrapper viewer__file-wrapper--hidden"
aria-hidden="true"
inert>
<component :is="previousFile.modal"
v-if="!previousFile.failed"
ref="previous-content"
v-bind="previousFile"
:file-list="fileList"
class="viewer__file"
@error="previousFailed" />
<Error v-else
:name="previousFile.basename" />
</div>

<!-- CURRENT -->
<component :is="currentFile.modal"
v-if="!currentFile.failed"
:key="currentFile | uniqueKey"
ref="content"
v-bind="currentFile"
:active="true"
:can-swipe.sync="canSwipe"
:can-zoom="canZoom"
:editing.sync="editing"
:file-list="fileList"
:is-full-screen="isFullscreen"
:is-sidebar-shown="isSidebarShown"
:loaded.sync="currentFile.loaded"
class="viewer__file viewer__file--active"
@error="currentFailed" />
<Error v-else
:name="currentFile.basename" />
<div :key="currentFile | uniqueKey" class="viewer__file-wrapper">
<component :is="currentFile.modal"
v-if="!currentFile.failed"
ref="content"
v-bind="currentFile"
:active="true"
:can-swipe.sync="canSwipe"
:can-zoom="canZoom"
:editing.sync="editing"
:file-list="fileList"
:is-full-screen="isFullscreen"
:is-sidebar-shown="isSidebarShown"
:loaded.sync="currentFile.loaded"
class="viewer__file viewer__file--active"
@error="currentFailed" />
<Error v-else
:name="currentFile.basename" />
</div>

<!-- NEXT -->
<component :is="nextFile.modal"
v-if="nextFile && !nextFile.failed"
<div v-if="nextFile"
:key="nextFile | uniqueKey"
ref="next-content"
v-bind="nextFile"
:file-list="fileList"
class="viewer__file--hidden viewer__file"
@error="nextFailed" />
<Error v-else-if="nextFile"
class="hidden-visually"
:name="nextFile.basename" />
class="viewer__file-wrapper viewer__file-wrapper--hidden"
aria-hidden="true"
inert>
<component :is="nextFile.modal"
v-if="!nextFile.failed"
ref="next-content"
v-bind="nextFile"
:file-list="fileList"
class="viewer__file"
@error="nextFailed" />
<Error v-else
:name="nextFile.basename" />
</div>
</div>
</NcModal>
</template>
Expand Down Expand Up @@ -1234,17 +1244,16 @@ export default {
}

&__content {
// center views
width: 100%;
height: 100%;
}

&__file-wrapper {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}

&__file {
transition: height 100ms ease,
width 100ms ease;

// display on page but make it invisible
&--hidden {
Expand All @@ -1254,6 +1263,11 @@ export default {
}
}

&__file {
transition: height 100ms ease,
width 100ms ease;
}

&.theme--dark:deep(.button-vue--vue-tertiary) {
&:hover {
background-color: rgba(255, 255, 255, .08) !important;
Expand Down
Loading