mirror of
https://github.com/nextcloud/server.git
synced 2026-06-12 10:10:49 -04:00
fix(theming): App order settings - ensure the focus is kept on button
When pressing a button for changing the app order that button should keep the focus after reordering the list. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
5c2610af7d
commit
9697df1ea5
2 changed files with 96 additions and 4 deletions
|
|
@ -23,20 +23,22 @@
|
|||
|
||||
<div class="order-selector-element__actions">
|
||||
<NcButton v-show="!isFirst && !app.default"
|
||||
ref="buttonUp"
|
||||
:aria-label="t('settings', 'Move up')"
|
||||
data-cy-app-order-button="up"
|
||||
type="tertiary-no-background"
|
||||
@click="$emit('move:up')">
|
||||
@click="moveUp">
|
||||
<template #icon>
|
||||
<IconArrowUp :size="20" />
|
||||
</template>
|
||||
</NcButton>
|
||||
<div v-show="isFirst || !!app.default" aria-hidden="true" class="order-selector-element__placeholder" />
|
||||
<NcButton v-show="!isLast && !app.default"
|
||||
ref="buttonDown"
|
||||
:aria-label="t('settings', 'Move down')"
|
||||
data-cy-app-order-button="down"
|
||||
type="tertiary-no-background"
|
||||
@click="$emit('move:down')">
|
||||
@click="moveDown">
|
||||
<template #icon>
|
||||
<IconArrowDown :size="20" />
|
||||
</template>
|
||||
|
|
@ -47,8 +49,10 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { PropType, defineComponent } from 'vue'
|
||||
import { defineComponent, nextTick, onUpdated, ref } from 'vue'
|
||||
|
||||
import IconArrowDown from 'vue-material-design-icons/ArrowDown.vue'
|
||||
import IconArrowUp from 'vue-material-design-icons/ArrowUp.vue'
|
||||
|
|
@ -86,8 +90,55 @@ export default defineComponent({
|
|||
'move:up': () => true,
|
||||
'move:down': () => true,
|
||||
},
|
||||
setup() {
|
||||
setup(props, { emit }) {
|
||||
const buttonUp = ref()
|
||||
const buttonDown = ref()
|
||||
|
||||
/**
|
||||
* Used to decide if we need to trigger focus() an a button on update
|
||||
*/
|
||||
let needsFocus = 0
|
||||
|
||||
/**
|
||||
* Handle move up, ensure focus is kept on the button
|
||||
*/
|
||||
const moveUp = () => {
|
||||
emit('move:up')
|
||||
needsFocus = 1 // request focus on buttonUp
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle move down, ensure focus is kept on the button
|
||||
*/
|
||||
const moveDown = () => {
|
||||
emit('move:down')
|
||||
needsFocus = -1 // request focus on buttonDown
|
||||
}
|
||||
|
||||
/**
|
||||
* onUpdated hook is used to reset the focus on the last used button (if requested)
|
||||
* If the button is now visible anymore (because this element is the first/last) then the opposite button is focussed
|
||||
*/
|
||||
onUpdated(() => {
|
||||
if (needsFocus !== 0) {
|
||||
// focus requested
|
||||
if ((needsFocus === 1 || props.isLast) && !props.isFirst) {
|
||||
// either requested to btn up and it is not the first, or it was requested to btn down but it is the last
|
||||
nextTick(() => buttonUp.value.$el.focus())
|
||||
} else {
|
||||
nextTick(() => buttonDown.value.$el.focus())
|
||||
}
|
||||
}
|
||||
needsFocus = 0
|
||||
})
|
||||
|
||||
return {
|
||||
buttonUp,
|
||||
buttonDown,
|
||||
|
||||
moveUp,
|
||||
moveDown,
|
||||
|
||||
t,
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -210,3 +210,44 @@ describe('User theming set app order with default app', () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('User theming app order list accessibility', () => {
|
||||
let user: User
|
||||
|
||||
before(() => {
|
||||
cy.resetAdminTheming()
|
||||
// Create random user for this test
|
||||
cy.createRandomUser().then(($user) => {
|
||||
user = $user
|
||||
cy.login($user)
|
||||
})
|
||||
})
|
||||
|
||||
after(() => {
|
||||
cy.deleteUser(user)
|
||||
})
|
||||
|
||||
it('See the app order settings', () => {
|
||||
cy.visit('/settings/user/theming')
|
||||
cy.get('[data-cy-app-order]').scrollIntoView()
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]').should('have.length', 2)
|
||||
})
|
||||
|
||||
it('click the first button', () => {
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:first-of-type [data-cy-app-order-button="down"]').should('be.visible').click()
|
||||
})
|
||||
|
||||
it('see the same app kept the focus', () => {
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:first-of-type [data-cy-app-order-button="down"]').should('not.have.focus')
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:last-of-type [data-cy-app-order-button="up"]').should('have.focus')
|
||||
})
|
||||
|
||||
it('click the last button', () => {
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:last-of-type [data-cy-app-order-button="up"]').should('be.visible').click()
|
||||
})
|
||||
|
||||
it('see the same app kept the focus', () => {
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:first-of-type [data-cy-app-order-button="down"]').should('have.focus')
|
||||
cy.get('[data-cy-app-order] [data-cy-app-order-element]:last-of-type [data-cy-app-order-button="up"]').should('not.have.focus')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue