about summary refs log tree commit diff
path: root/app/javascript/mastodon/features/emoji/emoji.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/mastodon/features/emoji/emoji.js')
-rw-r--r--app/javascript/mastodon/features/emoji/emoji.js38
1 files changed, 28 insertions, 10 deletions
diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js
index b70fc2b37..0f005dd50 100644
--- a/app/javascript/mastodon/features/emoji/emoji.js
+++ b/app/javascript/mastodon/features/emoji/emoji.js
@@ -1,3 +1,4 @@
+import { autoPlayGif } from '../../initial_state';
 import unicodeMapping from './emoji_unicode_mapping_light';
 import Trie from 'substring-trie';
 
@@ -5,13 +6,13 @@ const trie = new Trie(Object.keys(unicodeMapping));
 
 const assetHost = process.env.CDN_HOST || '';
 
-let allowAnimations = false;
-
 const emojify = (str, customEmojis = {}) => {
-  let rtn = '';
+  const tagCharsWithoutEmojis = '<&';
+  const tagCharsWithEmojis = Object.keys(customEmojis).length ? '<&:' : '<&';
+  let rtn = '', tagChars = tagCharsWithEmojis, invisible = 0;
   for (;;) {
     let match, i = 0, tag;
-    while (i < str.length && (tag = '<&:'.indexOf(str[i])) === -1 && !(match = trie.search(str.slice(i)))) {
+    while (i < str.length && (tag = tagChars.indexOf(str[i])) === -1 && (invisible || !(match = trie.search(str.slice(i))))) {
       i += str.codePointAt(i) < 65536 ? 1 : 2;
     }
     let rend, replacement = '';
@@ -27,7 +28,7 @@ const emojify = (str, customEmojis = {}) => {
         // now got a replacee as ':shortname:'
         // if you want additional emoji handler, add statements below which set replacement and return true.
         if (shortname in customEmojis) {
-          const filename = allowAnimations ? customEmojis[shortname].url : customEmojis[shortname].static_url;
+          const filename = autoPlayGif ? customEmojis[shortname].url : customEmojis[shortname].static_url;
           replacement = `<img draggable="false" class="emojione" alt="${shortname}" title="${shortname}" src="${filename}" />`;
           return true;
         }
@@ -35,7 +36,26 @@ const emojify = (str, customEmojis = {}) => {
       })()) rend = ++i;
     } else if (tag >= 0) { // <, &
       rend = str.indexOf('>;'[tag], i + 1) + 1;
-      if (!rend) break;
+      if (!rend) {
+        break;
+      }
+      if (tag === 0) {
+        if (invisible) {
+          if (str[i + 1] === '/') { // closing tag
+            if (!--invisible) {
+              tagChars = tagCharsWithEmojis;
+            }
+          } else if (str[rend - 2] !== '/') { // opening tag
+            invisible++;
+          }
+        } else {
+          if (str.startsWith('<span class="invisible">', i)) {
+            // avoid emojifying on invisible text
+            invisible = 1;
+            tagChars = tagCharsWithoutEmojis;
+          }
+        }
+      }
       i = rend;
     } else { // matched to unicode emoji
       const { filename, shortCode } = unicodeMapping[match];
@@ -51,14 +71,12 @@ const emojify = (str, customEmojis = {}) => {
 
 export default emojify;
 
-export const buildCustomEmojis = (customEmojis, overrideAllowAnimations = false) => {
+export const buildCustomEmojis = (customEmojis) => {
   const emojis = [];
 
-  allowAnimations = overrideAllowAnimations;
-
   customEmojis.forEach(emoji => {
     const shortcode = emoji.get('shortcode');
-    const url       = allowAnimations ? emoji.get('url') : emoji.get('static_url');
+    const url       = autoPlayGif ? emoji.get('url') : emoji.get('static_url');
     const name      = shortcode.replace(':', '');
 
     emojis.push({