Maintain last-known cursor position for inserting emojis
This commit is contained in:
parent
93335f8759
commit
a934759e66
5 changed files with 81 additions and 19 deletions
|
@ -1,11 +1,15 @@
|
|||
const { take } = require('lodash');
|
||||
const { getRecentEmojis } = require('./data');
|
||||
const { replaceColons } = require('../../ts/components/emoji/lib');
|
||||
const {
|
||||
replaceColons,
|
||||
hasVariation,
|
||||
} = require('../../ts/components/emoji/lib');
|
||||
|
||||
module.exports = {
|
||||
getInitialState,
|
||||
load,
|
||||
replaceColons,
|
||||
hasVariation,
|
||||
};
|
||||
|
||||
let initialState = null;
|
||||
|
|
|
@ -278,6 +278,12 @@
|
|||
|
||||
this.setupEmojiPickerButton();
|
||||
this.setupStickerPickerButton();
|
||||
|
||||
this.lastSelectionStart = 0;
|
||||
document.addEventListener(
|
||||
'selectionchange',
|
||||
this.updateLastSelectionStart.bind(this, undefined)
|
||||
);
|
||||
},
|
||||
|
||||
events: {
|
||||
|
@ -313,7 +319,17 @@
|
|||
setupEmojiPickerButton() {
|
||||
const props = {
|
||||
onPickEmoji: e => this.insertEmoji(e),
|
||||
onClose: () => this.focusMessageField(),
|
||||
onClose: () => {
|
||||
const textarea = this.$messageField[0];
|
||||
|
||||
textarea.focus();
|
||||
|
||||
const newPos = textarea.value.length;
|
||||
textarea.selectionStart = newPos;
|
||||
textarea.selectionEnd = newPos;
|
||||
|
||||
this.forceUpdateLastSelectionStart(newPos);
|
||||
},
|
||||
};
|
||||
|
||||
this.emojiButtonView = new Whisper.ReactWrapperView({
|
||||
|
@ -447,6 +463,10 @@
|
|||
|
||||
this.window.removeEventListener('resize', this.onResize);
|
||||
this.window.removeEventListener('focus', this.onFocus);
|
||||
document.removeEventListener(
|
||||
'selectionchange',
|
||||
this.updateLastSelectionStart
|
||||
);
|
||||
|
||||
window.autosize.destroy(this.$messageField);
|
||||
|
||||
|
@ -1052,6 +1072,7 @@
|
|||
focusMessageFieldAndClearDisabled() {
|
||||
this.$messageField.removeAttr('disabled');
|
||||
this.$messageField.focus();
|
||||
this.updateLastSelectionStart();
|
||||
},
|
||||
|
||||
async loadMoreMessages() {
|
||||
|
@ -1697,24 +1718,31 @@
|
|||
},
|
||||
|
||||
insertEmoji({ shortName, skinTone }) {
|
||||
const colons = `:${shortName}:${
|
||||
skinTone ? `:skin-tone-${skinTone}:` : ''
|
||||
}`;
|
||||
const skinReplacement = window.Signal.Emojis.hasVariation(
|
||||
shortName,
|
||||
skinTone
|
||||
)
|
||||
? `:skin-tone-${skinTone}:`
|
||||
: '';
|
||||
|
||||
const colons = `:${shortName}:${skinReplacement}`;
|
||||
|
||||
const textarea = this.$messageField[0];
|
||||
if (textarea.selectionStart || textarea.selectionStart === 0) {
|
||||
const startPos = textarea.selectionStart;
|
||||
const endPos = textarea.selectionEnd;
|
||||
const hasFocus = document.activeElement === textarea;
|
||||
const startPos = hasFocus
|
||||
? textarea.selectionStart
|
||||
: this.lastSelectionStart;
|
||||
const endPos = hasFocus ? textarea.selectionEnd : this.lastSelectionStart;
|
||||
|
||||
textarea.value =
|
||||
textarea.value.substring(0, startPos) +
|
||||
colons +
|
||||
textarea.value.substring(endPos, textarea.value.length);
|
||||
textarea.selectionStart = startPos + colons.length;
|
||||
textarea.selectionEnd = startPos + colons.length;
|
||||
} else {
|
||||
textarea.value += colons;
|
||||
}
|
||||
textarea.value =
|
||||
textarea.value.substring(0, startPos) +
|
||||
colons +
|
||||
textarea.value.substring(endPos, textarea.value.length);
|
||||
const newPos = startPos + colons.length;
|
||||
textarea.selectionStart = newPos;
|
||||
textarea.selectionEnd = newPos;
|
||||
this.forceUpdateLastSelectionStart(newPos);
|
||||
this.forceUpdateMessageFieldSize({});
|
||||
},
|
||||
|
||||
async setQuoteMessage(messageId) {
|
||||
|
@ -1853,6 +1881,18 @@
|
|||
this.debouncedMaybeGrabLinkPreview();
|
||||
},
|
||||
|
||||
updateLastSelectionStart(newPos) {
|
||||
if (document.activeElement === this.$messageField[0]) {
|
||||
this.forceUpdateLastSelectionStart(newPos);
|
||||
}
|
||||
},
|
||||
|
||||
forceUpdateLastSelectionStart(
|
||||
newPos = this.$messageField[0].selectionStart
|
||||
) {
|
||||
this.lastSelectionStart = newPos;
|
||||
},
|
||||
|
||||
maybeGrabLinkPreview() {
|
||||
// Don't generate link previews if user has turned them off
|
||||
if (!storage.get('linkPreviews', false)) {
|
||||
|
|
|
@ -292,7 +292,6 @@
|
|||
color: $color-light-90;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
outline: 0;
|
||||
z-index: 5;
|
||||
resize: none;
|
||||
font-size: 1em;
|
||||
font-family: inherit;
|
||||
|
|
|
@ -158,6 +158,25 @@ export function unifiedToEmoji(unified: string) {
|
|||
.join('');
|
||||
}
|
||||
|
||||
export function hasVariation(shortName: string, skinTone: number = 0) {
|
||||
if (skinTone === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const base = dataByShortName[shortName];
|
||||
if (!base) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skinTone > 0 && base.skin_variations) {
|
||||
const toneKey = skinTones[skinTone - 1];
|
||||
|
||||
return Boolean(base.skin_variations[toneKey]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function convertShortName(shortName: string, skinTone: number = 0) {
|
||||
const base = dataByShortName[shortName];
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@
|
|||
"rule": "jQuery-load(",
|
||||
"path": "js/modules/emojis.js",
|
||||
"line": "async function load() {",
|
||||
"lineNumber": 13,
|
||||
"lineNumber": 17,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2019-05-23T22:27:53.554Z"
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue