feat: pressing / or s focuses search input (#1855)
This commit is contained in:
parent
430ab4db4c
commit
07f23c5990
14
src/routes/_actions/goToSearch.js
Normal file
14
src/routes/_actions/goToSearch.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { store } from '../_store/store'
|
||||
import { goto } from '../../../__sapper__/client'
|
||||
import { emit } from '../_utils/eventBus'
|
||||
|
||||
// Go to the search page, and also focus the search input. For accessibility
|
||||
// and usability reasons, this only happens on pressing these particular hotkeys.
|
||||
export async function goToSearch () {
|
||||
if (store.get().currentPage === 'search') {
|
||||
emit('focusSearchInput')
|
||||
} else {
|
||||
store.set({ focusSearchInput: true })
|
||||
goto('/search')
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<Shortcut key="g n" on:pressed="goto('/notifications')"/>
|
||||
<Shortcut key="g c" on:pressed="goto('/community')"/>
|
||||
<Shortcut key="g d" on:pressed="goto('/direct')"/>
|
||||
<Shortcut key="s|/" on:pressed="goto('/search')"/>
|
||||
<Shortcut key="s|/" on:pressed="goToSearch()"/>
|
||||
<Shortcut key="h|?" on:pressed="showShortcutHelpDialog()"/>
|
||||
<Shortcut key="c|7" on:pressed="showComposeDialog()"/>
|
||||
{#if !$leftRightChangesFocus}
|
||||
|
@ -23,6 +23,7 @@
|
|||
import { importShowComposeDialog } from './dialog/asyncDialogs/importShowComposeDialog'
|
||||
import { store } from '../_store/store'
|
||||
import { normalizePageName } from '../_utils/normalizePageName'
|
||||
import { goToSearch } from '../_actions/goToSearch'
|
||||
|
||||
export default {
|
||||
store: () => store,
|
||||
|
@ -34,6 +35,7 @@
|
|||
console.log('nav shortcuts')
|
||||
},
|
||||
goto,
|
||||
goToSearch,
|
||||
async showShortcutHelpDialog () {
|
||||
const showShortcutHelpDialog = await importShowShortcutHelpDialog()
|
||||
showShortcutHelpDialog()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<form class="search-input-form" on:submit="onSubmit(event)">
|
||||
<div class="search-input-wrapper">
|
||||
<input type="search"
|
||||
<input id="the-search-input"
|
||||
type="search"
|
||||
class="search-input"
|
||||
placeholder="Search"
|
||||
aria-label="Search input"
|
||||
|
@ -61,8 +62,17 @@
|
|||
import { doSearch } from '../../_actions/search'
|
||||
import SearchResults from './SearchResults.html'
|
||||
import SvgIcon from '../SvgIcon.html'
|
||||
import { on } from '../../_utils/eventBus'
|
||||
import { tryToFocusElement } from '../../_utils/tryToFocusElement'
|
||||
|
||||
export default {
|
||||
oncreate () {
|
||||
on('focusSearchInput', this, () => this.focusSearchInput()) // user typed hotkey on this page itself
|
||||
if (this.store.get().focusSearchInput) { // we arrived here from a goto via the search hotkey
|
||||
this.store.set({ focusSearchInput: false }) // reset
|
||||
this.focusSearchInput()
|
||||
}
|
||||
},
|
||||
store: () => store,
|
||||
components: {
|
||||
LoadingPage,
|
||||
|
@ -70,9 +80,13 @@
|
|||
SvgIcon
|
||||
},
|
||||
methods: {
|
||||
async onSubmit (e) {
|
||||
onSubmit (e) {
|
||||
e.preventDefault()
|
||||
doSearch()
|
||||
e.stopPropagation()
|
||||
/* no await */ doSearch()
|
||||
},
|
||||
focusSearchInput () {
|
||||
tryToFocusElement('the-search-input')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
48
tests/spec/040-shortcuts-search.js
Normal file
48
tests/spec/040-shortcuts-search.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import {
|
||||
getActiveElementTagName,
|
||||
getNthStatus,
|
||||
getUrl,
|
||||
searchButton, searchInput, searchNavButton
|
||||
} from '../utils'
|
||||
import { loginAsFoobar } from '../roles'
|
||||
import { Selector as $ } from 'testcafe'
|
||||
|
||||
fixture`040-shortcuts-search.js`
|
||||
.page`http://localhost:4002`
|
||||
|
||||
test('Pressing / goes to search and focuses input but does not prevent left/right hotkeys afterwards', async t => {
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
.expect(getNthStatus(1).exists).ok()
|
||||
.pressKey('/')
|
||||
.expect(getUrl()).contains('/search')
|
||||
.expect(getActiveElementTagName()).match(/input/i)
|
||||
.typeText(searchInput, 'foo', { paste: true })
|
||||
.click(searchButton) // unfocus from the input
|
||||
.expect(getActiveElementTagName()).notMatch(/input/i)
|
||||
.pressKey('right')
|
||||
.expect(getUrl()).contains('/settings')
|
||||
.pressKey('left')
|
||||
.expect(getUrl()).contains('/search')
|
||||
// search input is not autofocused if we didn't arrive via the search hotkeys
|
||||
.expect(getActiveElementTagName()).notMatch(/input/i)
|
||||
})
|
||||
|
||||
test('Pressing / focuses the search input if we are already on the search page', async t => {
|
||||
await loginAsFoobar(t)
|
||||
await t
|
||||
.click(searchNavButton)
|
||||
.expect(getUrl()).contains('/search')
|
||||
.expect(getActiveElementTagName()).notMatch(/input/i)
|
||||
.pressKey('/')
|
||||
.expect(getActiveElementTagName()).match(/input/i)
|
||||
})
|
||||
|
||||
test('Pressing / without logging in just goes to the search page', async t => {
|
||||
await t
|
||||
.expect(getUrl()).eql('http://localhost:4002/')
|
||||
.expect($('.main-content h1').innerText).eql('Pinafore')
|
||||
.pressKey('/')
|
||||
.expect(getUrl()).contains('/search')
|
||||
.expect(getActiveElementTagName()).notMatch(/input/i)
|
||||
})
|
|
@ -33,6 +33,7 @@ export const logInToInstanceLink = $('a[href="/settings/instances/add"]')
|
|||
export const copyPasteModeButton = $('.copy-paste-mode-button')
|
||||
export const oauthCodeInput = $('#oauthCodeInput')
|
||||
export const searchInput = $('.search-input')
|
||||
export const searchButton = $('button[aria-label=Search]')
|
||||
export const postStatusButton = $('.compose-box-button')
|
||||
export const showMoreButton = $('.more-items-header button')
|
||||
export const accountProfileName = $('.account-profile .account-profile-name')
|
||||
|
|
Loading…
Reference in a new issue