Add rainbow_flag to emoji support map

Tested on the following platforms that split the emoji into separate
characters currently.
 - Windows 10 FCU
    - Chrome 62.0.3202.89
    - Firefox 57.0b14
    - MS Edge 41.16299.15.0
 - macOS 10.12.6
    - Chrome 63.0.3239.40
    - Safari 11.0.1 (12604.3.5.1.1)
    - Firefox 57.0
 - Ubuntu 16.04
    - Chromium 62.0.3202.75
    - Firefox 56.0
This commit is contained in:
Eric Eastwood 2017-11-14 15:59:23 -06:00
parent b5b3586543
commit 9e5db3e261
4 changed files with 61 additions and 12 deletions

View file

@ -7,6 +7,17 @@ function isFlagEmoji(emojiUnicode) {
return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint;
}
// Tested on mac OS 10.12.6 and Windows 10 FCU, it renders as two separate characters
const baseFlagCodePoint = 127987; // parseInt('1F3F3', 16)
const rainbowCodePoint = 127752; // parseInt('1F308', 16)
function isRainbowFlagEmoji(emojiUnicode) {
const characters = Array.from(emojiUnicode);
// Length 4 because flags are made of 2 characters which are surrogate pairs
return emojiUnicode.length === 4 &&
characters[0].codePointAt(0) === baseFlagCodePoint &&
characters[1].codePointAt(0) === rainbowCodePoint;
}
// Chrome <57 renders keycaps oddly
// See https://bugs.chromium.org/p/chromium/issues/detail?id=632294
// Same issue on Windows also fixed in Chrome 57, http://i.imgur.com/rQF7woO.png
@ -57,9 +68,11 @@ function isPersonZwjEmoji(emojiUnicode) {
// in `isEmojiUnicodeSupported` logic
function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isFlagResult = isFlagEmoji(emojiUnicode);
const isRainbowFlagResult = isRainbowFlagEmoji(emojiUnicode);
return (
(unicodeSupportMap.flag && isFlagResult) ||
!isFlagResult
(unicodeSupportMap.rainbowFlag && isRainbowFlagResult) ||
(!isFlagResult && !isRainbowFlagResult)
);
}
@ -113,6 +126,7 @@ function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVe
export {
isEmojiUnicodeSupported as default,
isFlagEmoji,
isRainbowFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,

View file

@ -1,5 +1,7 @@
import AccessorUtilities from '../../lib/utils/accessor';
const GL_EMOJI_VERSION = '0.2.0';
const unicodeSupportTestMap = {
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
// occupationZwj: '\u{1F468}\u{200D}\u{1F393}',
@ -13,6 +15,7 @@ const unicodeSupportTestMap = {
horseRacing: '\u{1F3C7}\u{1F3FF}',
// US flag, http://emojipedia.org/flags/
flag: '\u{1F1FA}\u{1F1F8}',
rainbowFlag: '\u{1F3F3}\u{1F308}',
// http://emojipedia.org/modifiers/
skinToneModifier: [
// spy_tone5
@ -141,23 +144,31 @@ function generateUnicodeSupportMap(testMap) {
}
export default function getUnicodeSupportMap() {
let unicodeSupportMap;
let userAgentFromCache;
const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
if (isLocalStorageAvailable) userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
let glEmojiVersionFromCache;
let userAgentFromCache;
if (isLocalStorageAvailable) {
glEmojiVersionFromCache = window.localStorage.getItem('gl-emoji-version');
userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
}
let unicodeSupportMap;
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) {
// swallow
}
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
if (
!unicodeSupportMap ||
glEmojiVersionFromCache !== GL_EMOJI_VERSION ||
userAgentFromCache !== navigator.userAgent
) {
unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap);
if (isLocalStorageAvailable) {
window.localStorage.setItem('gl-emoji-version', GL_EMOJI_VERSION);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
}

View file

@ -21,13 +21,18 @@ describe('Unicode Support Map', () => {
});
it('should call .getItem and .setItem', () => {
const allArgs = window.localStorage.setItem.calls.allArgs();
const getArgs = window.localStorage.getItem.calls.allArgs();
const setArgs = window.localStorage.setItem.calls.allArgs();
expect(window.localStorage.getItem).toHaveBeenCalledWith('gl-emoji-user-agent');
expect(allArgs[0][0]).toBe('gl-emoji-user-agent');
expect(allArgs[0][1]).toBe(navigator.userAgent);
expect(allArgs[1][0]).toBe('gl-emoji-unicode-support-map');
expect(allArgs[1][1]).toBe(stringSupportMap);
expect(getArgs[0][0]).toBe('gl-emoji-version');
expect(getArgs[1][0]).toBe('gl-emoji-user-agent');
expect(setArgs[0][0]).toBe('gl-emoji-version');
expect(setArgs[0][1]).toBe('0.2.0');
expect(setArgs[1][0]).toBe('gl-emoji-user-agent');
expect(setArgs[1][1]).toBe(navigator.userAgent);
expect(setArgs[2][0]).toBe('gl-emoji-unicode-support-map');
expect(setArgs[2][1]).toBe(stringSupportMap);
});
});

View file

@ -1,6 +1,7 @@
import { glEmojiTag } from '~/emoji';
import isEmojiUnicodeSupported, {
isFlagEmoji,
isRainbowFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
@ -217,6 +218,24 @@ describe('gl_emoji', () => {
});
});
describe('isRainbowFlagEmoji', () => {
it('should gracefully handle empty string', () => {
expect(isRainbowFlagEmoji('')).toBeFalsy();
});
it('should detect rainbow_flag', () => {
expect(isRainbowFlagEmoji('🏳🌈')).toBeTruthy();
});
it('should not detect flag_white on its\' own', () => {
expect(isRainbowFlagEmoji('🏳')).toBeFalsy();
});
it('should not detect rainbow on its\' own', () => {
expect(isRainbowFlagEmoji('🌈')).toBeFalsy();
});
it('should not detect flag_white with something else', () => {
expect(isRainbowFlagEmoji('🏳🔵')).toBeFalsy();
});
});
describe('isKeycapEmoji', () => {
it('should gracefully handle empty string', () => {
expect(isKeycapEmoji('')).toBeFalsy();