Fix caret position after inserting suggestions (fixes #281)

master
Thibaut Girka 7 years ago
parent d8793e1bee
commit 18d9a7fd71
  1. 11
      app/javascript/flavours/glitch/features/composer/index.js
  2. 8
      app/javascript/flavours/glitch/reducers/compose.js

@ -56,6 +56,7 @@ function mapStateToProps (state) {
advancedOptions: state.getIn(['compose', 'advanced_options']), advancedOptions: state.getIn(['compose', 'advanced_options']),
amUnlocked: !state.getIn(['accounts', me, 'locked']), amUnlocked: !state.getIn(['accounts', me, 'locked']),
focusDate: state.getIn(['compose', 'focusDate']), focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
isSubmitting: state.getIn(['compose', 'is_submitting']), isSubmitting: state.getIn(['compose', 'is_submitting']),
isUploading: state.getIn(['compose', 'is_uploading']), isUploading: state.getIn(['compose', 'is_uploading']),
layout: state.getIn(['local_settings', 'layout']), layout: state.getIn(['local_settings', 'layout']),
@ -117,7 +118,6 @@ const handlers = {
handleEmoji (data) { handleEmoji (data) {
const { textarea: { selectionStart } } = this; const { textarea: { selectionStart } } = this;
const { onInsertEmoji } = this.props; const { onInsertEmoji } = this.props;
this.caretPos = selectionStart + data.native.length + 1;
if (onInsertEmoji) { if (onInsertEmoji) {
onInsertEmoji(selectionStart, data); onInsertEmoji(selectionStart, data);
} }
@ -139,7 +139,6 @@ const handlers = {
// Selects a suggestion from the autofill. // Selects a suggestion from the autofill.
handleSelect (tokenStart, token, value) { handleSelect (tokenStart, token, value) {
const { onSelectSuggestion } = this.props; const { onSelectSuggestion } = this.props;
this.caretPos = null;
if (onSelectSuggestion) { if (onSelectSuggestion) {
onSelectSuggestion(tokenStart, token, value); onSelectSuggestion(tokenStart, token, value);
} }
@ -191,7 +190,6 @@ class Composer extends React.Component {
assignHandlers(this, handlers); assignHandlers(this, handlers);
// Instance variables. // Instance variables.
this.caretPos = null;
this.textarea = null; this.textarea = null;
} }
@ -220,11 +218,11 @@ class Composer extends React.Component {
// everyone else from the conversation. // everyone else from the conversation.
componentDidUpdate (prevProps) { componentDidUpdate (prevProps) {
const { const {
caretPos,
textarea, textarea,
} = this; } = this;
const { const {
focusDate, focusDate,
caretPosition,
isSubmitting, isSubmitting,
preselectDate, preselectDate,
text, text,
@ -238,8 +236,8 @@ class Composer extends React.Component {
selectionStart = text.search(/\s/) + 1; selectionStart = text.search(/\s/) + 1;
selectionEnd = text.length; selectionEnd = text.length;
break; break;
case !isNaN(caretPos) && caretPos !== null: case !isNaN(caretPosition) && caretPosition !== null:
selectionStart = selectionEnd = caretPos; selectionStart = selectionEnd = caretPosition;
break; break;
default: default:
selectionStart = selectionEnd = text.length; selectionStart = selectionEnd = text.length;
@ -396,6 +394,7 @@ Composer.propTypes = {
advancedOptions: ImmutablePropTypes.map, advancedOptions: ImmutablePropTypes.map,
amUnlocked: PropTypes.bool, amUnlocked: PropTypes.bool,
focusDate: PropTypes.instanceOf(Date), focusDate: PropTypes.instanceOf(Date),
caretPosition: PropTypes.number,
isSubmitting: PropTypes.bool, isSubmitting: PropTypes.bool,
isUploading: PropTypes.bool, isUploading: PropTypes.bool,
layout: PropTypes.string, layout: PropTypes.string,

@ -56,6 +56,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_submitting: false, is_submitting: false,
@ -148,6 +149,7 @@ function continueThread (state, status) {
map.update('media_attachments', list => list.clear()); map.update('media_attachments', list => list.clear());
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', null);
map.set('preselectDate', new Date()); map.set('preselectDate', new Date());
}); });
} }
@ -159,7 +161,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'))) {
@ -187,6 +188,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());
}); });
}; };
@ -197,6 +199,7 @@ const insertEmoji = (state, position, emojiData) => {
return state.withMutations(map => { return state.withMutations(map => {
map.update('text', oldText => `${oldText.slice(0, position)}${emoji}\u200B${oldText.slice(position)}`); map.update('text', oldText => `${oldText.slice(0, position)}${emoji}\u200B${oldText.slice(position)}`);
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', position + emoji.length + 1);
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
}); });
}; };
@ -278,6 +281,7 @@ export default function compose(state = initialState, action) {
map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(action.status.get('content')) })) map => map.merge(new ImmutableMap({ do_not_federate: /👁\ufe0f?\u200b?(?:<\/p>)?$/.test(action.status.get('content')) }))
); );
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());
@ -325,6 +329,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:
@ -332,6 +337,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:

Loading…
Cancel
Save