Merge branch 'compose-refactor' into 'master'

Fix composer issues

Closes #95, #86, and #116

See merge request soapbox-pub/soapbox-fe!25
This commit is contained in:
Alex Gleason 2020-05-26 23:31:08 +00:00
commit 6f76e1796b
3 changed files with 18 additions and 50 deletions

View file

@ -1,5 +1,4 @@
import React from 'react';
import { connect } from 'react-redux';
import CharacterCounter from './character_counter';
import Button from '../../../components/button';
import ImmutablePropTypes from 'react-immutable-proptypes';
@ -32,19 +31,11 @@ const messages = defineMessages({
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
});
const mapStateToProps = state => {
return {
maxTootChars: state.getIn(['instance', 'max_toot_chars']),
};
};
export default @connect(mapStateToProps)
@injectIntl
export default @injectIntl
class ComposeForm extends ImmutablePureComponent {
state = {
composeFocused: false,
caretPosition: 0,
}
static contextTypes = {
@ -60,7 +51,6 @@ class ComposeForm extends ImmutablePureComponent {
spoilerText: PropTypes.string,
focusDate: PropTypes.instanceOf(Date),
caretPosition: PropTypes.number,
preselectDate: PropTypes.instanceOf(Date),
isSubmitting: PropTypes.bool,
isChangingUpload: PropTypes.bool,
isUploading: PropTypes.bool,
@ -87,9 +77,6 @@ class ComposeForm extends ImmutablePureComponent {
handleChange = (e) => {
this.props.onChange(e.target.value);
this.setState({
caretPosition: e.target.selectionStart,
});
}
handleComposeFocus = () => {
@ -109,8 +96,10 @@ class ComposeForm extends ImmutablePureComponent {
return clickableAreaRef ? clickableAreaRef.current : this.form;
}
shouldCollapse = (e) => {
isClickOutside = (e) => {
return ![
// List of elements that shouldn't collapse the composer when clicked
// FIXME: Make this less brittle
this.getClickableArea(),
document.querySelector('.privacy-dropdown__dropdown'),
document.querySelector('.emoji-picker-dropdown__menu'),
@ -119,7 +108,7 @@ class ComposeForm extends ImmutablePureComponent {
}
handleClick = (e) => {
if (this.shouldCollapse(e)) {
if (this.isClickOutside(e)) {
this.handleClickOutside();
}
}
@ -168,43 +157,25 @@ class ComposeForm extends ImmutablePureComponent {
this.props.onChangeSpoilerText(e.target.value);
}
doFocus = () => {
if (!this.autosuggestTextarea) return;
this.autosuggestTextarea.textarea.focus();
}
setCursor = (start, end = start) => {
if (!this.autosuggestTextarea) return;
this.autosuggestTextarea.textarea.setSelectionRange(start, end);
}
componentDidMount() {
document.addEventListener('click', this.handleClick, true);
this.setCursor(this.props.text.length); // Set cursor at end
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClick, true);
}
componentDidUpdate(prevProps) {
if (!this.autosuggestTextarea) return;
// This statement does several things:
// - If we're beginning a reply, and,
// - 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;
// this provides a convenient shortcut to drop everyone else from the conversation.
let selectionEnd, selectionStart;
if (this.props.focusDate !== prevProps.focusDate) {
if (this.props.preselectDate !== prevProps.preselectDate) {
selectionEnd = this.props.text.length;
selectionStart = this.props.text.search(/\s/) + 1;
} else if (typeof this.state.caretPosition === 'number') {
selectionStart = this.state.caretPosition;
selectionEnd = this.state.caretPosition;
}
this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd);
this.autosuggestTextarea.textarea.focus();
} else {
if (this.props.preselectDate !== this.props.focusDate) {
selectionStart = selectionEnd = this.props.text.length + 1;
this.autosuggestTextarea.textarea.setSelectionRange(selectionStart, selectionEnd);
this.autosuggestTextarea.textarea.focus();
}
}
}
setAutosuggestTextarea = (c) => {
this.autosuggestTextarea = c;
}

View file

@ -19,13 +19,13 @@ const mapStateToProps = state => ({
privacy: state.getIn(['compose', 'privacy']),
focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
preselectDate: state.getIn(['compose', 'preselectDate']),
isSubmitting: state.getIn(['compose', 'is_submitting']),
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
isUploading: state.getIn(['compose', 'is_uploading']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
isModalOpen: state.get('modal').modalType === 'COMPOSE',
maxTootChars: state.getIn(['instance', 'max_toot_chars']),
});
const mapDispatchToProps = (dispatch) => ({

View file

@ -54,7 +54,6 @@ const initialState = ImmutableMap({
text: '',
focusDate: null,
caretPosition: null,
preselectDate: null,
in_reply_to: null,
is_composing: false,
is_submitting: false,
@ -237,8 +236,7 @@ export default function compose(state = initialState, action) {
case COMPOSE_CHANGE:
return state
.set('text', action.text)
.set('idempotencyKey', uuid())
.set('focusDate', new Date());
.set('idempotencyKey', uuid());
case COMPOSE_COMPOSING_CHANGE:
return state.set('is_composing', action.value);
case COMPOSE_REPLY:
@ -248,7 +246,6 @@ export default function compose(state = initialState, action) {
map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy')));
map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('preselectDate', new Date());
map.set('idempotencyKey', uuid());
if (action.status.get('spoiler_text').length > 0) {