mirror of
https://github.com/nextcloud/server.git
synced 2026-04-24 07:39:23 -04:00
Merge pull request #58462 from nextcloud/backport/58457/stable33
[stable33] fix(files): fix tab navigation from select all checkbox to batch actions
This commit is contained in:
commit
d4894b1af1
4 changed files with 58 additions and 4 deletions
|
|
@ -9,6 +9,7 @@
|
|||
@keyup.esc.exact="resetSelection">
|
||||
<NcCheckboxRadioSwitch
|
||||
v-bind="selectAllBind"
|
||||
:id="FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID"
|
||||
data-cy-files-list-selection-checkbox
|
||||
@update:model-value="onToggleAll" />
|
||||
</th>
|
||||
|
|
@ -79,6 +80,7 @@ import { t } from '@nextcloud/l10n'
|
|||
import { useHotKey } from '@nextcloud/vue/composables/useHotKey'
|
||||
import { defineComponent } from 'vue'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import { FILE_LIST_HEAD_FIRST_BATCH_ACTION_ID } from './FilesListTableHeaderActions.vue'
|
||||
import FilesListTableHeaderButton from './FilesListTableHeaderButton.vue'
|
||||
import { useFileListWidth } from '../composables/useFileListWidth.ts'
|
||||
import { useRouteParameters } from '../composables/useRouteParameters.ts'
|
||||
|
|
@ -88,6 +90,8 @@ import { useActiveStore } from '../store/active.ts'
|
|||
import { useFilesStore } from '../store/files.ts'
|
||||
import { useSelectionStore } from '../store/selection.ts'
|
||||
|
||||
export const FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID = 'files-list-header-select-all-checkbox'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FilesListTableHeader',
|
||||
|
||||
|
|
@ -137,6 +141,8 @@ export default defineComponent({
|
|||
|
||||
directory,
|
||||
isNarrow,
|
||||
|
||||
FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -196,6 +202,11 @@ export default defineComponent({
|
|||
})
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const selectAllCheckbox = document.getElementById(FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID)
|
||||
selectAllCheckbox?.addEventListener('keydown', this.onSelectAllCheckboxFocusOut)
|
||||
},
|
||||
|
||||
methods: {
|
||||
ariaSortForMode(mode: string): 'ascending' | 'descending' | undefined {
|
||||
if (this.sortingMode === mode) {
|
||||
|
|
@ -231,6 +242,18 @@ export default defineComponent({
|
|||
this.selectionStore.reset()
|
||||
},
|
||||
|
||||
onSelectAllCheckboxFocusOut(event: KeyboardEvent) {
|
||||
// If the user tabbed further and we have a batch action to tab to
|
||||
const firstBatchActionButton = document.getElementById(FILE_LIST_HEAD_FIRST_BATCH_ACTION_ID)
|
||||
if (event.code === 'Tab' && !event.shiftKey && !event.metaKey && firstBatchActionButton) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
firstBatchActionButton.focus()
|
||||
logger.debug('Focusing first batch action button')
|
||||
}
|
||||
},
|
||||
|
||||
t,
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
@close="openedSubmenu = null">
|
||||
<!-- Default actions list-->
|
||||
<NcActionButton
|
||||
v-for="action in enabledMenuActions"
|
||||
v-for="(action, idx) in enabledMenuActions"
|
||||
:id="idx === 0 ? FILE_LIST_HEAD_FIRST_BATCH_ACTION_ID : undefined"
|
||||
:key="action.id"
|
||||
:ref="`action-batch-${action.id}`"
|
||||
:class="{
|
||||
|
|
@ -84,6 +85,7 @@ import NcActionSeparator from '@nextcloud/vue/components/NcActionSeparator'
|
|||
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
|
||||
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
|
||||
import ArrowLeftIcon from 'vue-material-design-icons/ArrowLeft.vue'
|
||||
import { FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID } from './FilesListTableHeader.vue'
|
||||
import { useFileActions } from '../composables/useFileActions.ts'
|
||||
import { useFileListWidth } from '../composables/useFileListWidth.ts'
|
||||
import logger from '../logger.ts'
|
||||
|
|
@ -93,6 +95,8 @@ import { useActiveStore } from '../store/active.ts'
|
|||
import { useFilesStore } from '../store/files.ts'
|
||||
import { useSelectionStore } from '../store/selection.ts'
|
||||
|
||||
export const FILE_LIST_HEAD_FIRST_BATCH_ACTION_ID = 'files-list-head-first-batch-action'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FilesListTableHeaderActions',
|
||||
|
||||
|
|
@ -149,6 +153,8 @@ export default defineComponent({
|
|||
|
||||
boundariesElement,
|
||||
inlineActions,
|
||||
|
||||
FILE_LIST_HEAD_FIRST_BATCH_ACTION_ID,
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -269,6 +275,17 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const firstActionId = this.enabledMenuActions.at(0)?.id
|
||||
const firstButton = this.$refs.actionsMenu?.$refs?.[`action-batch-${firstActionId}`]
|
||||
if (firstButton) {
|
||||
firstButton.$el.focus()
|
||||
logger.debug('Focusing first batch action button')
|
||||
|
||||
firstButton.$el.addEventListener('focusout', this.onFirstButtonFocusOut)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* Get a cached note from the store
|
||||
|
|
@ -343,6 +360,20 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
|
||||
// When focusing out the first button outside the header actions
|
||||
// we can return back to the select all checkbox
|
||||
onFirstButtonFocusOut(event: FocusEvent) {
|
||||
// If the focus is still within this component, do nothing
|
||||
if (this.$el.contains(event.relatedTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
document.getElementById(FILES_LIST_HEADER_SELECT_ALL_CHECKBOX_ID)?.focus()
|
||||
logger.debug('Focusing select all checkbox again')
|
||||
},
|
||||
|
||||
t: translate,
|
||||
},
|
||||
})
|
||||
|
|
|
|||
4
dist/files-main.js
vendored
4
dist/files-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-main.js.map
vendored
2
dist/files-main.js.map
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue