Add support for sending room-local emoji (#209)

* Add support for sending room-local emoji

Does not add support for sending a room's emoji outside of that room, but enables users to
send an emoji if the packs in a room support it.  Does not include room emoji in the
picker YET.

* Amend PR #209: Don't freak out if the `pack` tag is missing

* Amending PR:  Refactor emojifier, use better method for retrieving packs

* Amending PR:  Improve resiliance to bad data in emoji state events

* Amend PR: Remove redundant code, fix crash on edit
This commit is contained in:
Emi 2021-12-28 23:26:17 -05:00 committed by GitHub
parent f9b70d65d8
commit 9ea9bf4035
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 174 additions and 76 deletions

View file

@ -113,6 +113,54 @@ function bindReplyToContent(roomId, reply, content) {
return newContent;
}
// Apply formatting to a plain text message
//
// This includes inserting any custom emoji that might be relevant, and (only if the
// user has enabled it in their settings) formatting the message using markdown.
function formatAndEmojifyText(room, text) {
const allEmoji = getShortcodeToEmoji(room);
// Start by applying markdown formatting (if relevant)
let formattedText;
if (settings.isMarkdown) {
formattedText = getFormattedBody(text);
} else {
formattedText = text;
}
// Check to see if there are any :shortcode-style-tags: in the message
Array.from(formattedText.matchAll(/\B:([\w-]+):\B/g))
// Then filter to only the ones corresponding to a valid emoji
.filter((match) => allEmoji.has(match[1]))
// Reversing the array ensures that indices are preserved as we start replacing
.reverse()
// Replace each :shortcode: with an <img/> tag
.forEach((shortcodeMatch) => {
const emoji = allEmoji.get(shortcodeMatch[1]);
// Render the tag that will replace the shortcode
let tag;
if (emoji.mxc) {
tag = `<img data-mx-emoticon="" src="${
emoji.mxc
}" alt=":${
emoji.shortcode
}:" title=":${
emoji.shortcode
}:" height="32" />`;
} else {
tag = emoji.unicode;
}
// Splice the tag into the text
formattedText = formattedText.substr(0, shortcodeMatch.index)
+ tag
+ formattedText.substr(shortcodeMatch.index + shortcodeMatch[0].length);
});
return formattedText;
}
class RoomsInput extends EventEmitter {
constructor(mx) {
super();
@ -201,54 +249,6 @@ class RoomsInput extends EventEmitter {
return this.roomIdToInput.get(roomId)?.isSending || false;
}
// Apply formatting to a plain text message
//
// This includes inserting any custom emoji that might be relevant, and (only if the
// user has enabled it in their settings) formatting the message using markdown.
formatAndEmojifyText(text) {
const allEmoji = getShortcodeToEmoji(this.matrixClient);
// Start by applying markdown formatting (if relevant)
let formattedText;
if (settings.isMarkdown) {
formattedText = getFormattedBody(text);
} else {
formattedText = text;
}
// Check to see if there are any :shortcode-style-tags: in the message
Array.from(formattedText.matchAll(/\B:([\w-]+):\B/g))
// Then filter to only the ones corresponding to a valid emoji
.filter((match) => allEmoji.has(match[1]))
// Reversing the array ensures that indices are preserved as we start replacing
.reverse()
// Replace each :shortcode: with an <img/> tag
.forEach((shortcodeMatch) => {
const emoji = allEmoji.get(shortcodeMatch[1]);
// Render the tag that will replace the shortcode
let tag;
if (emoji.mxc) {
tag = `<img data-mx-emoticon="" src="${
emoji.mxc
}" alt=":${
emoji.shortcode
}:" title=":${
emoji.shortcode
}:" height="32" />`;
} else {
tag = emoji.unicode;
}
// Splice the tag into the text
formattedText = formattedText.substr(0, shortcodeMatch.index)
+ tag
+ formattedText.substr(shortcodeMatch.index + shortcodeMatch[0].length);
});
return formattedText;
}
async sendInput(roomId) {
const input = this.getInput(roomId);
input.isSending = true;
@ -265,7 +265,10 @@ class RoomsInput extends EventEmitter {
};
// Apply formatting if relevant
const formattedBody = this.formatAndEmojifyText(input.message);
const formattedBody = formatAndEmojifyText(
this.matrixClient.getRoom(roomId),
input.message,
);
if (formattedBody !== input.message) {
// Formatting was applied, and we need to switch to custom HTML
content.format = 'org.matrix.custom.html';
@ -401,7 +404,10 @@ class RoomsInput extends EventEmitter {
};
// Apply formatting if relevant
const formattedBody = this.formatAndEmojifyText(editedBody);
const formattedBody = formatAndEmojifyText(
this.matrixClient.getRoom(roomId),
editedBody
);
if (formattedBody !== editedBody) {
content.formatted_body = ` * ${formattedBody}`;
content.format = 'org.matrix.custom.html';