kopia lustrzana https://github.com/nolanlawson/pinafore
				
				
				
			feat: pressing / or s focuses search input (#1855)
							rodzic
							
								
									430ab4db4c
								
							
						
					
					
						commit
						07f23c5990
					
				|  | @ -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') | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -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') | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Nolan Lawson
						Nolan Lawson