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