Don't autofocus the compose form (#16517)
When opening a page such as /web/timelines/home in a desktop browser, the cursor was automatically placed in the textarea of the compose form. When using the keyboard for navigation (using a browser plugin like vimium or vim vixen, or just to hit 'space' to scroll down a page), you have remember to leave the field before using that. Since you only visit the page to write a new post some of the time, this PR attempts to have nothing focused initially (and require the user to click or e.g. use 'tab' to focus the textarea). Tested: * /web/timeslines/home no longer autofocuses the compose box * pressing the 'n' hotkey still focuses the compose box * clicking 'reply' for a post still focuses the compose box * replying to a CW'ed post still focuses the compose box * introducing the CW field still focuses the CW field * introducing the CW field for a reply still focuses the CW field * removing the CW field still focuses the compose box * /web/statuses/new still autofocuses the compose box fixes #15862pull/41/head
parent
3656a6b9cc
commit
9f63c428e1
|
@ -16,7 +16,6 @@ import PollFormContainer from '../containers/poll_form_container';
|
||||||
import UploadFormContainer from '../containers/upload_form_container';
|
import UploadFormContainer from '../containers/upload_form_container';
|
||||||
import WarningContainer from '../containers/warning_container';
|
import WarningContainer from '../containers/warning_container';
|
||||||
import LanguageDropdown from '../containers/language_dropdown_container';
|
import LanguageDropdown from '../containers/language_dropdown_container';
|
||||||
import { isMobile } from '../../../is_mobile';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { countableText } from '../util/counter';
|
import { countableText } from '../util/counter';
|
||||||
|
@ -61,14 +60,14 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onChangeSpoilerText: PropTypes.func.isRequired,
|
onChangeSpoilerText: PropTypes.func.isRequired,
|
||||||
onPaste: PropTypes.func.isRequired,
|
onPaste: PropTypes.func.isRequired,
|
||||||
onPickEmoji: PropTypes.func.isRequired,
|
onPickEmoji: PropTypes.func.isRequired,
|
||||||
showSearch: PropTypes.bool,
|
autoFocus: PropTypes.bool,
|
||||||
anyMedia: PropTypes.bool,
|
anyMedia: PropTypes.bool,
|
||||||
isInReply: PropTypes.bool,
|
isInReply: PropTypes.bool,
|
||||||
singleColumn: PropTypes.bool,
|
singleColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
showSearch: false,
|
autoFocus: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleChange = (e) => {
|
handleChange = (e) => {
|
||||||
|
@ -154,7 +153,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
// - Replying to zero or one users, places the cursor at the end of the textbox.
|
// - Replying to zero or one users, places the cursor at the end of the textbox.
|
||||||
// - Replying to more than one user, selects any usernames past the first;
|
// - Replying to more than one user, selects any usernames past the first;
|
||||||
// this provides a convenient shortcut to drop everyone else from the conversation.
|
// this provides a convenient shortcut to drop everyone else from the conversation.
|
||||||
if (this.props.focusDate !== prevProps.focusDate) {
|
if (this.props.focusDate && this.props.focusDate !== prevProps.focusDate) {
|
||||||
let selectionEnd, selectionStart;
|
let selectionEnd, selectionStart;
|
||||||
|
|
||||||
if (this.props.preselectDate !== prevProps.preselectDate && this.props.isInReply) {
|
if (this.props.preselectDate !== prevProps.preselectDate && this.props.isInReply) {
|
||||||
|
@ -180,7 +179,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
} else if (this.props.spoiler !== prevProps.spoiler) {
|
} else if (this.props.spoiler !== prevProps.spoiler) {
|
||||||
if (this.props.spoiler) {
|
if (this.props.spoiler) {
|
||||||
this.spoilerText.input.focus();
|
this.spoilerText.input.focus();
|
||||||
} else {
|
} else if (prevProps.spoiler) {
|
||||||
this.autosuggestTextarea.textarea.focus();
|
this.autosuggestTextarea.textarea.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,7 +206,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, onPaste, showSearch } = this.props;
|
const { intl, onPaste, autoFocus } = this.props;
|
||||||
const disabled = this.props.isSubmitting;
|
const disabled = this.props.isSubmitting;
|
||||||
|
|
||||||
let publishText = '';
|
let publishText = '';
|
||||||
|
@ -257,7 +256,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
onSuggestionSelected={this.onSuggestionSelected}
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
onPaste={onPaste}
|
onPaste={onPaste}
|
||||||
autoFocus={!showSearch && !isMobile(window.innerWidth)}
|
autoFocus={autoFocus}
|
||||||
>
|
>
|
||||||
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
|
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ const mapStateToProps = state => ({
|
||||||
isEditing: state.getIn(['compose', 'id']) !== null,
|
isEditing: state.getIn(['compose', 'id']) !== null,
|
||||||
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
|
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
|
||||||
isUploading: state.getIn(['compose', 'is_uploading']),
|
isUploading: state.getIn(['compose', 'is_uploading']),
|
||||||
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
|
|
||||||
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
|
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,7 @@ import Icon from 'mastodon/components/icon';
|
||||||
import { logOut } from 'mastodon/utils/log_out';
|
import { logOut } from 'mastodon/utils/log_out';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
|
import { isMobile } from '../../is_mobile';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
||||||
|
@ -115,7 +116,7 @@ class Compose extends React.PureComponent {
|
||||||
<div className='drawer__inner' onFocus={this.onFocus}>
|
<div className='drawer__inner' onFocus={this.onFocus}>
|
||||||
<NavigationContainer onClose={this.onBlur} />
|
<NavigationContainer onClose={this.onBlur} />
|
||||||
|
|
||||||
<ComposeFormContainer />
|
<ComposeFormContainer autoFocus={!isMobile(window.innerWidth)} />
|
||||||
|
|
||||||
<div className='drawer__inner__mastodon'>
|
<div className='drawer__inner__mastodon'>
|
||||||
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
|
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
|
||||||
|
|
Loading…
Reference in New Issue