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 */ /* global Cookies */
const emojiMap = require('emoji-map'); import emojiMap from 'emojis/digests.json';
const emojiAliases = require('emoji-aliases'); import emojiAliases from 'emojis/aliases.json';
const glEmoji = require('./behaviors/gl_emoji'); import { glEmojiTag } from './behaviors/gl_emoji';
const glEmojiTag = glEmoji.glEmojiTag;
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const requestAnimationFrame = window.requestAnimationFrame || const requestAnimationFrame = window.requestAnimationFrame ||
...@@ -515,4 +513,4 @@ AwardsHandler.prototype.destroy = function destroy() { ...@@ -515,4 +513,4 @@ AwardsHandler.prototype.destroy = function destroy() {
$('.emoji-menu').remove(); $('.emoji-menu').remove();
}; };
module.exports = AwardsHandler; export default AwardsHandler;
const installCustomElements = require('document-register-element'); import installCustomElements from 'document-register-element';
const emojiMap = require('emoji-map'); import emojiMap from 'emojis/digests.json';
const emojiAliases = require('emoji-aliases'); import emojiAliases from 'emojis/aliases.json';
const generatedUnicodeSupportMap = require('./gl_emoji/unicode_support_map'); import { getUnicodeSupportMap } from './gl_emoji/unicode_support_map';
const spreadString = require('./gl_emoji/spread_string'); import { isEmojiUnicodeSupported } from './gl_emoji/is_emoji_unicode_supported';
installCustomElements(window); installCustomElements(window);
const generatedUnicodeSupportMap = getUnicodeSupportMap();
function emojiImageTag(name, src) { function emojiImageTag(name, src) {
return `<img class="emoji" title=":${name}:" alt=":${name}:" src="${src}" width="20" height="20" align="absmiddle" />`; return `<img class="emoji" title=":${name}:" alt=":${name}:" src="${src}" width="20" height="20" align="absmiddle" />`;
} }
...@@ -55,119 +57,9 @@ function glEmojiTag(inputName, options) { ...@@ -55,119 +57,9 @@ function glEmojiTag(inputName, options) {
`; `;
} }
// On Windows, flags render as two-letter country codes, see http://emojipedia.org/flags/ function installGlEmojiElement() {
const flagACodePoint = 127462; // parseInt('1F1E6', 16) const GlEmojiElementProto = Object.create(HTMLElement.prototype);
const flagZCodePoint = 127487; // parseInt('1F1FF', 16) GlEmojiElementProto.createdCallback = function createdCallback() {
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);
}
const GlEmojiElementProto = Object.create(HTMLElement.prototype);
GlEmojiElementProto.createdCallback = function createdCallback() {
const emojiUnicode = this.textContent.trim(); const emojiUnicode = this.textContent.trim();
const { const {
name, name,
...@@ -199,19 +91,15 @@ GlEmojiElementProto.createdCallback = function createdCallback() { ...@@ -199,19 +91,15 @@ GlEmojiElementProto.createdCallback = function createdCallback() {
this.innerHTML = emojiImageTag(name, src); this.innerHTML = emojiImageTag(name, src);
} }
} }
}; };
document.registerElement('gl-emoji', { document.registerElement('gl-emoji', {
prototype: GlEmojiElementProto, prototype: GlEmojiElementProto,
}); });
}
module.exports = { export {
emojiImageTag, installGlEmojiElement,
glEmojiTag, glEmojiTag,
isEmojiUnicodeSupported, emojiImageTag,
isFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
}; };
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) { ...@@ -47,4 +47,4 @@ function spreadString(str) {
return arr; return arr;
} }
module.exports = spreadString; export default spreadString;
...@@ -68,7 +68,7 @@ const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatche ...@@ -68,7 +68,7 @@ const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatche
// See 32px, https://i.imgur.com/htY6Zym.png // See 32px, https://i.imgur.com/htY6Zym.png
// See 16px, https://i.imgur.com/FPPsIF8.png // See 16px, https://i.imgur.com/FPPsIF8.png
const fontSize = 16; const fontSize = 16;
function testUnicodeSupportMap(testMap) { function generateUnicodeSupportMap(testMap) {
const testMapKeys = Object.keys(testMap); const testMapKeys = Object.keys(testMap);
const numTestEntries = testMapKeys const numTestEntries = testMapKeys
.reduce((list, testKey) => list.concat(testMap[testKey]), []).length; .reduce((list, testKey) => list.concat(testMap[testKey]), []).length;
...@@ -138,17 +138,24 @@ function testUnicodeSupportMap(testMap) { ...@@ -138,17 +138,24 @@ function testUnicodeSupportMap(testMap) {
return resultMap; return resultMap;
} }
let unicodeSupportMap; function getUnicodeSupportMap() {
const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent'); let unicodeSupportMap;
try { const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map')); unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) { } catch (err) {
// swallow // swallow
} }
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) { if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
unicodeSupportMap = testUnicodeSupportMap(unicodeSupportTestMap); unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent); window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap)); window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
}
return unicodeSupportMap;
} }
module.exports = unicodeSupportMap; export {
getUnicodeSupportMap,
generateUnicodeSupportMap,
};
require('string.prototype.codepointat'); import 'string.prototype.codepointat';
require('string.fromcodepoint'); 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 */ /* 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'); import emojiMap from 'emojis/digests.json';
const emojiAliases = require('emoji-aliases'); import emojiAliases from 'emojis/aliases.json';
const glEmoji = require('./behaviors/gl_emoji'); import { glEmojiTag } from '~/behaviors/gl_emoji';
const glEmojiTag = glEmoji.glEmojiTag;
// Creates the variables for setting up GFM auto-completion // Creates the variables for setting up GFM auto-completion
(function() { (function() {
......
This diff is collapsed.
...@@ -133,8 +133,7 @@ var config = { ...@@ -133,8 +133,7 @@ var config = {
extensions: ['.js', '.es6', '.js.es6'], extensions: ['.js', '.es6', '.js.es6'],
alias: { alias: {
'~': path.join(ROOT_PATH, 'app/assets/javascripts'), '~': path.join(ROOT_PATH, 'app/assets/javascripts'),
'emoji-map$': path.join(ROOT_PATH, 'fixtures/emojis/digests.json'), 'emojis': path.join(ROOT_PATH, 'fixtures/emojis'),
'emoji-aliases$': path.join(ROOT_PATH, 'fixtures/emojis/aliases.json'),
'empty_states': path.join(ROOT_PATH, 'app/views/shared/empty_states'), 'empty_states': path.join(ROOT_PATH, 'app/views/shared/empty_states'),
'icons': path.join(ROOT_PATH, 'app/views/shared/icons'), 'icons': path.join(ROOT_PATH, 'app/views/shared/icons'),
'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), '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 */ /* 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() { (function() {
var awardsHandler, lazyAssert, urlRoot, openAndWaitForEmojiMenu; var awardsHandler, lazyAssert, urlRoot, openAndWaitForEmojiMenu;
......
import '~/extensions/string';
import '~/extensions/array';
require('~/extensions/string'); import { glEmojiTag } from '~/behaviors/gl_emoji';
require('~/extensions/array'); import {
isEmojiUnicodeSupported,
const glEmoji = require('~/behaviors/gl_emoji'); isFlagEmoji,
isKeycapEmoji,
const glEmojiTag = glEmoji.glEmojiTag; isSkinToneComboEmoji,
const isEmojiUnicodeSupported = glEmoji.isEmojiUnicodeSupported; isHorceRacingSkinToneComboEmoji,
const isFlagEmoji = glEmoji.isFlagEmoji; isPersonZwjEmoji,
const isKeycapEmoji = glEmoji.isKeycapEmoji; } from '~/behaviors/gl_emoji/is_emoji_unicode_supported';
const isSkinToneComboEmoji = glEmoji.isSkinToneComboEmoji;
const isHorceRacingSkinToneComboEmoji = glEmoji.isHorceRacingSkinToneComboEmoji;
const isPersonZwjEmoji = glEmoji.isPersonZwjEmoji;
const emptySupportMap = { const emptySupportMap = {
personZwj: false, 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