Fix caret position after selected suggestion and media upload (#7595)

* Fix media upload reseting caret position to last inserted emoji

* Fix caret position after inserting suggestions (fixes #6089)
This commit is contained in:
ThibG 2018-05-23 15:20:15 +02:00 committed by Eugen Rochko
parent 6d99a0b652
commit d8864b9e9d
3 changed files with 11 additions and 7 deletions

View file

@ -40,6 +40,7 @@ export default class ComposeForm extends ImmutablePureComponent {
privacy: PropTypes.string, privacy: PropTypes.string,
spoiler_text: PropTypes.string, spoiler_text: PropTypes.string,
focusDate: PropTypes.instanceOf(Date), focusDate: PropTypes.instanceOf(Date),
caretPosition: PropTypes.number,
preselectDate: PropTypes.instanceOf(Date), preselectDate: PropTypes.instanceOf(Date),
is_submitting: PropTypes.bool, is_submitting: PropTypes.bool,
is_uploading: PropTypes.bool, is_uploading: PropTypes.bool,
@ -96,7 +97,6 @@ export default class ComposeForm extends ImmutablePureComponent {
} }
onSuggestionSelected = (tokenStart, token, value) => { onSuggestionSelected = (tokenStart, token, value) => {
this._restoreCaret = null;
this.props.onSuggestionSelected(tokenStart, token, value); this.props.onSuggestionSelected(tokenStart, token, value);
} }
@ -116,9 +116,9 @@ export default class ComposeForm extends ImmutablePureComponent {
if (this.props.preselectDate !== prevProps.preselectDate) { if (this.props.preselectDate !== prevProps.preselectDate) {
selectionEnd = this.props.text.length; selectionEnd = this.props.text.length;
selectionStart = this.props.text.search(/\s/) + 1; selectionStart = this.props.text.search(/\s/) + 1;
} else if (typeof this._restoreCaret === 'number') { } else if (typeof this.props.caretPosition === 'number') {
selectionStart = this._restoreCaret; selectionStart = this.props.caretPosition;
selectionEnd = this._restoreCaret; selectionEnd = this.props.caretPosition;
} else { } else {
selectionEnd = this.props.text.length; selectionEnd = this.props.text.length;
selectionStart = selectionEnd; selectionStart = selectionEnd;
@ -138,10 +138,8 @@ export default class ComposeForm extends ImmutablePureComponent {
handleEmojiPick = (data) => { handleEmojiPick = (data) => {
const { text } = this.props; const { text } = this.props;
const position = this.autosuggestTextarea.textarea.selectionStart; const position = this.autosuggestTextarea.textarea.selectionStart;
const emojiChar = data.native;
const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]); const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]);
this._restoreCaret = position + emojiChar.length + 1 + (needsSpace ? 1 : 0);
this.props.onPickEmoji(position, data, needsSpace); this.props.onPickEmoji(position, data, needsSpace);
} }

View file

@ -19,6 +19,7 @@ const mapStateToProps = state => ({
spoiler_text: state.getIn(['compose', 'spoiler_text']), spoiler_text: state.getIn(['compose', 'spoiler_text']),
privacy: state.getIn(['compose', 'privacy']), privacy: state.getIn(['compose', 'privacy']),
focusDate: state.getIn(['compose', 'focusDate']), focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
preselectDate: state.getIn(['compose', 'preselectDate']), preselectDate: state.getIn(['compose', 'preselectDate']),
is_submitting: state.getIn(['compose', 'is_submitting']), is_submitting: state.getIn(['compose', 'is_submitting']),
is_uploading: state.getIn(['compose', 'is_uploading']), is_uploading: state.getIn(['compose', 'is_uploading']),

View file

@ -44,6 +44,7 @@ const initialState = ImmutableMap({
privacy: null, privacy: null,
text: '', text: '',
focusDate: null, focusDate: null,
caretPosition: null,
preselectDate: null, preselectDate: null,
in_reply_to: null, in_reply_to: null,
is_composing: false, is_composing: false,
@ -91,7 +92,6 @@ function appendMedia(state, media) {
map.update('media_attachments', list => list.push(media)); map.update('media_attachments', list => list.push(media));
map.set('is_uploading', false); map.set('is_uploading', false);
map.set('resetFileKey', Math.floor((Math.random() * 0x10000))); map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
map.set('focusDate', new Date());
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) { if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) {
@ -119,6 +119,7 @@ const insertSuggestion = (state, position, token, completion) => {
map.set('suggestion_token', null); map.set('suggestion_token', null);
map.update('suggestions', ImmutableList(), list => list.clear()); map.update('suggestions', ImmutableList(), list => list.clear());
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', position + completion.length + 1);
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
}); });
}; };
@ -142,6 +143,7 @@ const insertEmoji = (state, position, emojiData, needsSpace) => {
return state.merge({ return state.merge({
text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`, text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
focusDate: new Date(), focusDate: new Date(),
caretPosition: position + emoji.length + 1,
idempotencyKey: uuid(), idempotencyKey: uuid(),
}); });
}; };
@ -216,6 +218,7 @@ export default function compose(state = initialState, action) {
map.set('text', statusToTextMentions(state, action.status)); map.set('text', statusToTextMentions(state, action.status));
map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy'))); map.set('privacy', privacyPreference(action.status.get('visibility'), state.get('default_privacy')));
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('preselectDate', new Date()); map.set('preselectDate', new Date());
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
@ -259,6 +262,7 @@ export default function compose(state = initialState, action) {
return state.withMutations(map => { return state.withMutations(map => {
map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' ')); map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
}); });
case COMPOSE_DIRECT: case COMPOSE_DIRECT:
@ -266,6 +270,7 @@ export default function compose(state = initialState, action) {
map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' ')); map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
map.set('privacy', 'direct'); map.set('privacy', 'direct');
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
}); });
case COMPOSE_SUGGESTIONS_CLEAR: case COMPOSE_SUGGESTIONS_CLEAR: