Commit d163ac26 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'update-native-unicode-emojis-with-harmony-modules' into 'master'

Update emojis to use harmony modules (import/export)

See merge request !9784
parents 92bb0d8f ee993014
/* global Cookies */
const emojiMap = require('emoji-map');
const emojiAliases = require('emoji-aliases');
const glEmoji = require('./behaviors/gl_emoji');
const glEmojiTag = glEmoji.glEmojiTag;
import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json';
import { glEmojiTag } from './behaviors/gl_emoji';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const requestAnimationFrame = window.requestAnimationFrame ||
......@@ -515,4 +513,4 @@ AwardsHandler.prototype.destroy = function destroy() {
$('.emoji-menu').remove();
};
module.exports = AwardsHandler;
export default AwardsHandler;
const installCustomElements = require('document-register-element');
const emojiMap = require('emoji-map');
const emojiAliases = require('emoji-aliases');
const generatedUnicodeSupportMap = require('./gl_emoji/unicode_support_map');
const spreadString = require('./gl_emoji/spread_string');
import installCustomElements from 'document-register-element';
import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json';
import { getUnicodeSupportMap } from './gl_emoji/unicode_support_map';
import { isEmojiUnicodeSupported } from './gl_emoji/is_emoji_unicode_supported';
installCustomElements(window);
const generatedUnicodeSupportMap = getUnicodeSupportMap();
function emojiImageTag(name, src) {
return `<img class="emoji" title=":${name}:" alt=":${name}:" src="${src}" width="20" height="20" align="absmiddle" />`;
}
......@@ -55,163 +57,49 @@ function glEmojiTag(inputName, options) {
`;
}
// On Windows, flags render as two-letter country codes, see http://emojipedia.org/flags/
const flagACodePoint = 127462; // parseInt('1F1E6', 16)
const flagZCodePoint = 127487; // parseInt('1F1FF', 16)
function isFlagEmoji(emojiUnicode) {
const cp = emojiUnicode.codePointAt(0);
// Length 4 because flags are made of 2 characters which are surrogate pairs
return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint;
}
// 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
function isKeycapEmoji(emojiUnicode) {
return emojiUnicode.length === 3 && emojiUnicode[2] === '\u20E3';
}
// Check for a skin tone variation emoji which aren't always supported
const tone1 = 127995;// parseInt('1F3FB', 16)
const tone5 = 127999;// parseInt('1F3FF', 16)
function isSkinToneComboEmoji(emojiUnicode) {
return emojiUnicode.length > 2 && spreadString(emojiUnicode).some((char) => {
const cp = char.codePointAt(0);
return cp >= tone1 && cp <= tone5;
});
}
// macOS supports most skin tone emoji's but
// doesn't support the skin tone versions of horse racing
const horseRacingCodePoint = 127943;// parseInt('1F3C7', 16)
function isHorceRacingSkinToneComboEmoji(emojiUnicode) {
return spreadString(emojiUnicode)[0].codePointAt(0) === horseRacingCodePoint &&
isSkinToneComboEmoji(emojiUnicode);
}
// Check for `family_*`, `kiss_*`, `couple_*`
// For ex. Windows 8.1 Firefox 51.0.1, doesn't support these
const zwj = 8205; // parseInt('200D', 16)
const personStartCodePoint = 128102; // parseInt('1F466', 16)
const personEndCodePoint = 128105; // parseInt('1F469', 16)
function isPersonZwjEmoji(emojiUnicode) {
let hasPersonEmoji = false;
let hasZwj = false;
spreadString(emojiUnicode).forEach((character) => {
const cp = character.codePointAt(0);
if (cp === zwj) {
hasZwj = true;
} else if (cp >= personStartCodePoint && cp <= personEndCodePoint) {
hasPersonEmoji = true;
function installGlEmojiElement() {
const GlEmojiElementProto = Object.create(HTMLElement.prototype);
GlEmojiElementProto.createdCallback = function createdCallback() {
const emojiUnicode = this.textContent.trim();
const {
name,
unicodeVersion,
fallbackSrc,
fallbackSpriteClass,
} = this.dataset;
const isEmojiUnicode = this.childNodes && Array.prototype.every.call(
this.childNodes,
childNode => childNode.nodeType === 3,
);
const hasImageFallback = fallbackSrc && fallbackSrc.length > 0;
const hasCssSpriteFalback = fallbackSpriteClass && fallbackSpriteClass.length > 0;
if (
isEmojiUnicode &&
!isEmojiUnicodeSupported(generatedUnicodeSupportMap, emojiUnicode, unicodeVersion)
) {
// CSS sprite fallback takes precedence over image fallback
if (hasCssSpriteFalback) {
// IE 11 doesn't like adding multiple at once :(
this.classList.add('emoji-icon');
this.classList.add(fallbackSpriteClass);
} else if (hasImageFallback) {
this.innerHTML = emojiImageTag(name, fallbackSrc);
} else {
const src = assembleFallbackImageSrc(name);
this.innerHTML = emojiImageTag(name, src);
}
}
});
return hasPersonEmoji && hasZwj;
}
// Helper so we don't have to run `isFlagEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isFlagResult = isFlagEmoji(emojiUnicode);
return (
(unicodeSupportMap.flag && isFlagResult) ||
!isFlagResult
);
}
// Helper so we don't have to run `isSkinToneComboEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) {
const isSkinToneResult = isSkinToneComboEmoji(emojiUnicode);
return (
(unicodeSupportMap.skinToneModifier && isSkinToneResult) ||
!isSkinToneResult
);
}
// Helper func so we don't have to run `isHorceRacingSkinToneComboEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isHorseRacingSkinToneResult = isHorceRacingSkinToneComboEmoji(emojiUnicode);
return (
(unicodeSupportMap.horseRacing && isHorseRacingSkinToneResult) ||
!isHorseRacingSkinToneResult
);
}
// Helper so we don't have to run `isPersonZwjEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isPersonZwjResult = isPersonZwjEmoji(emojiUnicode);
return (
(unicodeSupportMap.personZwj && isPersonZwjResult) ||
!isPersonZwjResult
);
}
// Takes in a support map and determines whether
// the given unicode emoji is supported on the platform.
//
// Combines all the edge case tests into a one-stop shop method
function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVersion) {
const isOlderThanChrome57 = unicodeSupportMap.meta && unicodeSupportMap.meta.isChrome &&
unicodeSupportMap.meta.chromeVersion < 57;
};
// For comments about each scenario, see the comments above each individual respective function
return unicodeSupportMap[unicodeVersion] &&
!(isOlderThanChrome57 && isKeycapEmoji(emojiUnicode)) &&
checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) &&
checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) &&
checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) &&
checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode);
document.registerElement('gl-emoji', {
prototype: GlEmojiElementProto,
});
}
const GlEmojiElementProto = Object.create(HTMLElement.prototype);
GlEmojiElementProto.createdCallback = function createdCallback() {
const emojiUnicode = this.textContent.trim();
const {
name,
unicodeVersion,
fallbackSrc,
fallbackSpriteClass,
} = this.dataset;
const isEmojiUnicode = this.childNodes && Array.prototype.every.call(
this.childNodes,
childNode => childNode.nodeType === 3,
);
const hasImageFallback = fallbackSrc && fallbackSrc.length > 0;
const hasCssSpriteFalback = fallbackSpriteClass && fallbackSpriteClass.length > 0;
if (
isEmojiUnicode &&
!isEmojiUnicodeSupported(generatedUnicodeSupportMap, emojiUnicode, unicodeVersion)
) {
// CSS sprite fallback takes precedence over image fallback
if (hasCssSpriteFalback) {
// IE 11 doesn't like adding multiple at once :(
this.classList.add('emoji-icon');
this.classList.add(fallbackSpriteClass);
} else if (hasImageFallback) {
this.innerHTML = emojiImageTag(name, fallbackSrc);
} else {
const src = assembleFallbackImageSrc(name);
this.innerHTML = emojiImageTag(name, src);
}
}
};
document.registerElement('gl-emoji', {
prototype: GlEmojiElementProto,
});
module.exports = {
emojiImageTag,
export {
installGlEmojiElement,
glEmojiTag,
isEmojiUnicodeSupported,
isFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
emojiImageTag,
};
import spreadString from './spread_string';
// On Windows, flags render as two-letter country codes, see http://emojipedia.org/flags/
const flagACodePoint = 127462; // parseInt('1F1E6', 16)
const flagZCodePoint = 127487; // parseInt('1F1FF', 16)
function isFlagEmoji(emojiUnicode) {
const cp = emojiUnicode.codePointAt(0);
// Length 4 because flags are made of 2 characters which are surrogate pairs
return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint;
}
// 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
function isKeycapEmoji(emojiUnicode) {
return emojiUnicode.length === 3 && emojiUnicode[2] === '\u20E3';
}
// Check for a skin tone variation emoji which aren't always supported
const tone1 = 127995;// parseInt('1F3FB', 16)
const tone5 = 127999;// parseInt('1F3FF', 16)
function isSkinToneComboEmoji(emojiUnicode) {
return emojiUnicode.length > 2 && spreadString(emojiUnicode).some((char) => {
const cp = char.codePointAt(0);
return cp >= tone1 && cp <= tone5;
});
}
// macOS supports most skin tone emoji's but
// doesn't support the skin tone versions of horse racing
const horseRacingCodePoint = 127943;// parseInt('1F3C7', 16)
function isHorceRacingSkinToneComboEmoji(emojiUnicode) {
return spreadString(emojiUnicode)[0].codePointAt(0) === horseRacingCodePoint &&
isSkinToneComboEmoji(emojiUnicode);
}
// Check for `family_*`, `kiss_*`, `couple_*`
// For ex. Windows 8.1 Firefox 51.0.1, doesn't support these
const zwj = 8205; // parseInt('200D', 16)
const personStartCodePoint = 128102; // parseInt('1F466', 16)
const personEndCodePoint = 128105; // parseInt('1F469', 16)
function isPersonZwjEmoji(emojiUnicode) {
let hasPersonEmoji = false;
let hasZwj = false;
spreadString(emojiUnicode).forEach((character) => {
const cp = character.codePointAt(0);
if (cp === zwj) {
hasZwj = true;
} else if (cp >= personStartCodePoint && cp <= personEndCodePoint) {
hasPersonEmoji = true;
}
});
return hasPersonEmoji && hasZwj;
}
// Helper so we don't have to run `isFlagEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isFlagResult = isFlagEmoji(emojiUnicode);
return (
(unicodeSupportMap.flag && isFlagResult) ||
!isFlagResult
);
}
// Helper so we don't have to run `isSkinToneComboEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) {
const isSkinToneResult = isSkinToneComboEmoji(emojiUnicode);
return (
(unicodeSupportMap.skinToneModifier && isSkinToneResult) ||
!isSkinToneResult
);
}
// Helper func so we don't have to run `isHorceRacingSkinToneComboEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isHorseRacingSkinToneResult = isHorceRacingSkinToneComboEmoji(emojiUnicode);
return (
(unicodeSupportMap.horseRacing && isHorseRacingSkinToneResult) ||
!isHorseRacingSkinToneResult
);
}
// Helper so we don't have to run `isPersonZwjEmoji` twice
// in `isEmojiUnicodeSupported` logic
function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isPersonZwjResult = isPersonZwjEmoji(emojiUnicode);
return (
(unicodeSupportMap.personZwj && isPersonZwjResult) ||
!isPersonZwjResult
);
}
// Takes in a support map and determines whether
// the given unicode emoji is supported on the platform.
//
// Combines all the edge case tests into a one-stop shop method
function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVersion) {
const isOlderThanChrome57 = unicodeSupportMap.meta && unicodeSupportMap.meta.isChrome &&
unicodeSupportMap.meta.chromeVersion < 57;
// For comments about each scenario, see the comments above each individual respective function
return unicodeSupportMap[unicodeVersion] &&
!(isOlderThanChrome57 && isKeycapEmoji(emojiUnicode)) &&
checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) &&
checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) &&
checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) &&
checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode);
}
export {
isEmojiUnicodeSupported,
isFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
};
......@@ -47,4 +47,4 @@ function spreadString(str) {
return arr;
}
module.exports = spreadString;
export default spreadString;
......@@ -68,7 +68,7 @@ const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatche
// See 32px, https://i.imgur.com/htY6Zym.png
// See 16px, https://i.imgur.com/FPPsIF8.png
const fontSize = 16;
function testUnicodeSupportMap(testMap) {
function generateUnicodeSupportMap(testMap) {
const testMapKeys = Object.keys(testMap);
const numTestEntries = testMapKeys
.reduce((list, testKey) => list.concat(testMap[testKey]), []).length;
......@@ -138,17 +138,24 @@ function testUnicodeSupportMap(testMap) {
return resultMap;
}
let unicodeSupportMap;
const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) {
// swallow
}
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
unicodeSupportMap = testUnicodeSupportMap(unicodeSupportTestMap);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
function getUnicodeSupportMap() {
let unicodeSupportMap;
const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) {
// swallow
}
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
}
return unicodeSupportMap;
}
module.exports = unicodeSupportMap;
export {
getUnicodeSupportMap,
generateUnicodeSupportMap,
};
require('string.prototype.codepointat');
require('string.fromcodepoint');
import 'string.prototype.codepointat';
import 'string.fromcodepoint';
/* eslint-disable func-names, space-before-function-paren, no-template-curly-in-string, comma-dangle, object-shorthand, quotes, dot-notation, no-else-return, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-param-reassign, no-useless-escape, prefer-template, consistent-return, wrap-iife, prefer-arrow-callback, camelcase, no-unused-vars, no-useless-return, vars-on-top, max-len */
const emojiMap = require('emoji-map');
const emojiAliases = require('emoji-aliases');
const glEmoji = require('./behaviors/gl_emoji');
const glEmojiTag = glEmoji.glEmojiTag;
import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json';
import { glEmojiTag } from '~/behaviors/gl_emoji';
// Creates the variables for setting up GFM auto-completion
(function() {
......
This diff is collapsed.
......@@ -133,8 +133,7 @@ var config = {
extensions: ['.js', '.es6', '.js.es6'],
alias: {
'~': path.join(ROOT_PATH, 'app/assets/javascripts'),
'emoji-map$': path.join(ROOT_PATH, 'fixtures/emojis/digests.json'),
'emoji-aliases$': path.join(ROOT_PATH, 'fixtures/emojis/aliases.json'),
'emojis': path.join(ROOT_PATH, 'fixtures/emojis'),
'empty_states': path.join(ROOT_PATH, 'app/views/shared/empty_states'),
'icons': path.join(ROOT_PATH, 'app/views/shared/icons'),
'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'),
......
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */
require('es6-promise').polyfill();
import promisePolyfill from 'es6-promise';
import AwardsHandler from '~/awards_handler';
const AwardsHandler = require('~/awards_handler');
promisePolyfill.polyfill();
(function() {
var awardsHandler, lazyAssert, urlRoot, openAndWaitForEmojiMenu;
......
import '~/extensions/string';
import '~/extensions/array';
require('~/extensions/string');
require('~/extensions/array');
const glEmoji = require('~/behaviors/gl_emoji');
const glEmojiTag = glEmoji.glEmojiTag;
const isEmojiUnicodeSupported = glEmoji.isEmojiUnicodeSupported;
const isFlagEmoji = glEmoji.isFlagEmoji;
const isKeycapEmoji = glEmoji.isKeycapEmoji;
const isSkinToneComboEmoji = glEmoji.isSkinToneComboEmoji;
const isHorceRacingSkinToneComboEmoji = glEmoji.isHorceRacingSkinToneComboEmoji;
const isPersonZwjEmoji = glEmoji.isPersonZwjEmoji;
import { glEmojiTag } from '~/behaviors/gl_emoji';
import {
isEmojiUnicodeSupported,
isFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
} from '~/behaviors/gl_emoji/is_emoji_unicode_supported';
const emptySupportMap = {
personZwj: false,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment