From 782224c99151665470b138add583d50df17b4380 Mon Sep 17 00:00:00 2001 From: MIYAGI Hikaru Date: Tue, 7 Nov 2017 22:48:13 +0900 Subject: [PATCH] Avoid emojifying on invisible text (#5558) --- .../features/emoji/__tests__/emoji-test.js | 16 +++++++++++ .../mastodon/features/emoji/emoji.js | 27 ++++++++++++++++--- app/lib/formatter.rb | 26 +++++++++++++----- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js index 6364021727..372459c783 100644 --- a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js +++ b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js @@ -57,5 +57,21 @@ describe('emoji', () => { it('does an emoji whose filename is irregular', () => { expect(emojify('↙️')).toEqual('↙️'); }); + + it('avoid emojifying on invisible text', () => { + expect(emojify('example.com/te')) + .toEqual('example.com/te'); + expect(emojify('', { ':luigi:': { static_url: 'luigi.exe' } })) + .toEqual(''); + }); + + it('avoid emojifying on invisible text with nested tags', () => { + expect(emojify('πŸ˜‡')) + .toEqual('πŸ˜‡'); + expect(emojify('πŸ˜‡')) + .toEqual('πŸ˜‡'); + expect(emojify('πŸ˜‡')) + .toEqual('πŸ˜‡'); + }); }); }); diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js index bda33ca260..0f005dd504 100644 --- a/app/javascript/mastodon/features/emoji/emoji.js +++ b/app/javascript/mastodon/features/emoji/emoji.js @@ -7,10 +7,12 @@ const trie = new Trie(Object.keys(unicodeMapping)); const assetHost = process.env.CDN_HOST || ''; 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 = ''; @@ -34,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('