add option to remove emoji from user display names (#450)
* add option to remove emoji from user display names fixes #449 * slight memory perf improvement
This commit is contained in:
		
							parent
							
								
									350667e5df
								
							
						
					
					
						commit
						37e12e8d73
					
				
					 9 changed files with 92 additions and 5 deletions
				
			
		
							
								
								
									
										5
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -4177,6 +4177,11 @@
 | 
			
		|||
        "minimalistic-crypto-utils": "^1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "emoji-regex": {
 | 
			
		||||
      "version": "7.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-lnvttkzAlYW8WpFPiStPWyd/YdS02cFsYwXwWqnbKY43fMgUeUx+vzW1Zaozu34n4Fm7sxygi8+SEL6dcks/hQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "emojis-list": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,7 @@
 | 
			
		|||
    "chokidar": "^2.0.4",
 | 
			
		||||
    "cross-env": "^5.2.0",
 | 
			
		||||
    "css-loader": "^1.0.0",
 | 
			
		||||
    "emoji-regex": "^7.0.0",
 | 
			
		||||
    "escape-html": "^1.0.3",
 | 
			
		||||
    "esm": "^3.0.77",
 | 
			
		||||
    "events": "^3.0.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,17 +5,29 @@
 | 
			
		|||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import { emojifyText } from '../../_utils/emojifyText'
 | 
			
		||||
  import { emojifyText, removeEmoji } from '../../_utils/emojifyText'
 | 
			
		||||
  import { store } from '../../_store/store'
 | 
			
		||||
  import escapeHtml from 'escape-html'
 | 
			
		||||
  import emojiRegex from 'emoji-regex'
 | 
			
		||||
 | 
			
		||||
  let theEmojiRegex
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    store: () => store,
 | 
			
		||||
    computed: {
 | 
			
		||||
      emojis: ({ account }) => (account.emojis || []),
 | 
			
		||||
      accountName: ({ account }) => (account.display_name || account.username),
 | 
			
		||||
      massagedAccountName: ({ accountName, emojis, $autoplayGifs }) => {
 | 
			
		||||
      massagedAccountName: ({ accountName, emojis, $autoplayGifs, $omitEmojiInDisplayNames }) => {
 | 
			
		||||
        accountName = escapeHtml(accountName)
 | 
			
		||||
 | 
			
		||||
        if ($omitEmojiInDisplayNames) { // display name emoji are annoying to some screenreader users
 | 
			
		||||
          theEmojiRegex = theEmojiRegex || emojiRegex() // only init when needed
 | 
			
		||||
          let emojiFreeAccountName = removeEmoji(accountName.replace(theEmojiRegex, ''), emojis).trim()
 | 
			
		||||
          if (emojiFreeAccountName) {
 | 
			
		||||
            return emojiFreeAccountName // only remove emoji if the resulting username is non-empty
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return emojifyText(accountName, emojis, $autoplayGifs)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,11 @@
 | 
			
		|||
             bind:checked="$reduceMotion" on:change="$save()">
 | 
			
		||||
      <label for="choice-reduce-motion">Reduce motion in UI animations</label>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="setting-group">
 | 
			
		||||
      <input type="checkbox" id="choice-omit-emoji-in-display-names"
 | 
			
		||||
             bind:checked="$omitEmojiInDisplayNames" on:change="$save()">
 | 
			
		||||
      <label for="choice-omit-emoji-in-display-names">Remove emoji from user display names</label>
 | 
			
		||||
    </div>
 | 
			
		||||
  </form>
 | 
			
		||||
 | 
			
		||||
</SettingsLayout>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ const KEYS_TO_STORE_IN_LOCAL_STORAGE = new Set([
 | 
			
		|||
  'autoplayGifs',
 | 
			
		||||
  'markMediaAsSensitive',
 | 
			
		||||
  'reduceMotion',
 | 
			
		||||
  'omitEmojiInDisplayNames',
 | 
			
		||||
  'pinnedPages',
 | 
			
		||||
  'composeData'
 | 
			
		||||
])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import { replaceAll } from './strings'
 | 
			
		||||
 | 
			
		||||
export function emojifyText (text, emojis, autoplayGifs) {
 | 
			
		||||
  if (emojis && emojis.length) {
 | 
			
		||||
  if (emojis) {
 | 
			
		||||
    for (let emoji of emojis) {
 | 
			
		||||
      let urlToUse = autoplayGifs ? emoji.url : emoji.static_url
 | 
			
		||||
      let shortcodeWithColons = `:${emoji.shortcode}:`
 | 
			
		||||
| 
						 | 
				
			
			@ -15,3 +15,13 @@ export function emojifyText (text, emojis, autoplayGifs) {
 | 
			
		|||
  }
 | 
			
		||||
  return text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function removeEmoji (text, emojis) {
 | 
			
		||||
  if (emojis) {
 | 
			
		||||
    for (let emoji of emojis) {
 | 
			
		||||
      let shortcodeWithColons = `:${emoji.shortcode}:`
 | 
			
		||||
      text = replaceAll(text, shortcodeWithColons, '')
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return text
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
export function replaceAll (string, replacee, replacement) {
 | 
			
		||||
  if (!string.length || !replacee.length || !replacement.length) {
 | 
			
		||||
  if (!string.length || !replacee.length) {
 | 
			
		||||
    return string
 | 
			
		||||
  }
 | 
			
		||||
  let idx
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,10 @@
 | 
			
		|||
import { loginAsFoobar } from '../roles'
 | 
			
		||||
import { displayNameInComposeBox, getNthStatusSelector, getUrl, sleep } from '../utils'
 | 
			
		||||
import {
 | 
			
		||||
  displayNameInComposeBox, generalSettingsButton, getNthStatusSelector, getUrl, homeNavButton,
 | 
			
		||||
  removeEmojiFromDisplayNamesInput,
 | 
			
		||||
  settingsNavButton,
 | 
			
		||||
  sleep
 | 
			
		||||
} from '../utils'
 | 
			
		||||
import { updateUserDisplayNameAs } from '../serverActions'
 | 
			
		||||
import { Selector as $ } from 'testcafe'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25,3 +30,49 @@ test('Cannot XSS using display name HTML', async t => {
 | 
			
		|||
  await t
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('<script>alert("pwn")</script>')
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('Can remove emoji from user display names', async t => {
 | 
			
		||||
  await updateUserDisplayNameAs('foobar', '🌈 foo :blobpats: 🌈')
 | 
			
		||||
  await sleep(1000)
 | 
			
		||||
  await loginAsFoobar(t)
 | 
			
		||||
  await t
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('🌈 foo  🌈')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).ok()
 | 
			
		||||
    .click(settingsNavButton)
 | 
			
		||||
    .click(generalSettingsButton)
 | 
			
		||||
    .click(removeEmojiFromDisplayNamesInput)
 | 
			
		||||
    .expect(removeEmojiFromDisplayNamesInput.checked).ok()
 | 
			
		||||
    .click(homeNavButton)
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('foo')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).notOk()
 | 
			
		||||
    .click(settingsNavButton)
 | 
			
		||||
    .click(generalSettingsButton)
 | 
			
		||||
    .click(removeEmojiFromDisplayNamesInput)
 | 
			
		||||
    .expect(removeEmojiFromDisplayNamesInput.checked).notOk()
 | 
			
		||||
    .click(homeNavButton)
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('🌈 foo  🌈')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).ok()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('Cannot remove emoji from user display names if result would be empty', async t => {
 | 
			
		||||
  await updateUserDisplayNameAs('foobar', '🌈 :blobpats: 🌈')
 | 
			
		||||
  await sleep(1000)
 | 
			
		||||
  await loginAsFoobar(t)
 | 
			
		||||
  await t
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('🌈  🌈')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).ok()
 | 
			
		||||
    .click(settingsNavButton)
 | 
			
		||||
    .click(generalSettingsButton)
 | 
			
		||||
    .click(removeEmojiFromDisplayNamesInput)
 | 
			
		||||
    .expect(removeEmojiFromDisplayNamesInput.checked).ok()
 | 
			
		||||
    .click(homeNavButton)
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('🌈  🌈')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).ok()
 | 
			
		||||
    .click(settingsNavButton)
 | 
			
		||||
    .click(generalSettingsButton)
 | 
			
		||||
    .click(removeEmojiFromDisplayNamesInput)
 | 
			
		||||
    .expect(removeEmojiFromDisplayNamesInput.checked).notOk()
 | 
			
		||||
    .click(homeNavButton)
 | 
			
		||||
    .expect(displayNameInComposeBox.innerText).eql('🌈  🌈')
 | 
			
		||||
    .expect($('.compose-box-display-name img').exists).ok()
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,8 @@ export const followsButton = $('.account-profile-details > *:nth-child(2)')
 | 
			
		|||
export const followersButton = $('.account-profile-details > *:nth-child(3)')
 | 
			
		||||
export const avatarInComposeBox = $('.compose-box-avatar')
 | 
			
		||||
export const displayNameInComposeBox = $('.compose-box-display-name')
 | 
			
		||||
export const generalSettingsButton = $('a[href="/settings/general"]')
 | 
			
		||||
export const removeEmojiFromDisplayNamesInput = $('#choice-omit-emoji-in-display-names')
 | 
			
		||||
 | 
			
		||||
export const favoritesCountElement = $('.status-favs-reblogs:nth-child(3)').addCustomDOMProperties({
 | 
			
		||||
  innerCount: el => parseInt(el.innerText, 10)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue