Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Greiling <mike@pixelcog.com>2017-06-23 22:08:06 +0300
committerMike Greiling <mike@pixelcog.com>2017-06-23 22:23:20 +0300
commitd099744dd41af983e5a02f64375b60a8cf6c539f (patch)
tree5da66cf0627f47eca8cb929fe4bc80a6b2cad1d1 /app/assets/javascripts/behaviors
parent5a044dc25b1c04da6253577a3934e857a0c0bd0d (diff)
centralize emoji helper methods
Diffstat (limited to 'app/assets/javascripts/behaviors')
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji.js5
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji/is_emoji_name_valid.js11
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji/is_emoji_unicode_supported.js120
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js172
4 files changed, 1 insertions, 307 deletions
diff --git a/app/assets/javascripts/behaviors/gl_emoji.js b/app/assets/javascripts/behaviors/gl_emoji.js
index ca6117c4fd6..06eb698378c 100644
--- a/app/assets/javascripts/behaviors/gl_emoji.js
+++ b/app/assets/javascripts/behaviors/gl_emoji.js
@@ -1,8 +1,5 @@
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';
+import { emojiMap, emojiAliases, isEmojiUnicodeSupported, getUnicodeSupportMap } from '../emoji';
installCustomElements(window);
diff --git a/app/assets/javascripts/behaviors/gl_emoji/is_emoji_name_valid.js b/app/assets/javascripts/behaviors/gl_emoji/is_emoji_name_valid.js
deleted file mode 100644
index be4aeb32c46..00000000000
--- a/app/assets/javascripts/behaviors/gl_emoji/is_emoji_name_valid.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import emojiMap from 'emojis/digests.json';
-import emojiAliases from 'emojis/aliases.json';
-
-function isEmojiNameValid(inputName) {
- const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ?
- emojiAliases[inputName] : inputName;
-
- return name && emojiMap[name];
-}
-
-export default isEmojiNameValid;
diff --git a/app/assets/javascripts/behaviors/gl_emoji/is_emoji_unicode_supported.js b/app/assets/javascripts/behaviors/gl_emoji/is_emoji_unicode_supported.js
deleted file mode 100644
index 4f8884d05ac..00000000000
--- a/app/assets/javascripts/behaviors/gl_emoji/is_emoji_unicode_supported.js
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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 && Array.from(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) {
- const firstCharacter = Array.from(emojiUnicode)[0];
- return firstCharacter && firstCharacter.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;
- Array.from(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,
-};
diff --git a/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js b/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js
deleted file mode 100644
index 257df55e54f..00000000000
--- a/app/assets/javascripts/behaviors/gl_emoji/unicode_support_map.js
+++ /dev/null
@@ -1,172 +0,0 @@
-import AccessorUtilities from '../../lib/utils/accessor';
-
-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}',
- // woman, biking (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
- // sexZwj: '\u{1F6B4}\u{200D}\u{2640}',
- // family_mwgb
- // Windows 8.1, Firefox 51.0.1 does not support `family_`, `kiss_`, `couple_`
- personZwj: '\u{1F468}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}',
- // horse_racing_tone5
- // Special case that is not supported on macOS 10.12 even though `skinToneModifier` succeeds
- horseRacing: '\u{1F3C7}\u{1F3FF}',
- // US flag, http://emojipedia.org/flags/
- flag: '\u{1F1FA}\u{1F1F8}',
- // http://emojipedia.org/modifiers/
- skinToneModifier: [
- // spy_tone5
- '\u{1F575}\u{1F3FF}',
- // person_with_ball_tone5
- '\u{26F9}\u{1F3FF}',
- // angel_tone5
- '\u{1F47C}\u{1F3FF}',
- ],
- // rofl, http://emojipedia.org/unicode-9.0/
- '9.0': '\u{1F923}',
- // metal, http://emojipedia.org/unicode-8.0/
- '8.0': '\u{1F918}',
- // spy, http://emojipedia.org/unicode-7.0/
- '7.0': '\u{1F575}',
- // expressionless, http://emojipedia.org/unicode-6.1/
- 6.1: '\u{1F611}',
- // japanese_goblin, http://emojipedia.org/unicode-6.0/
- '6.0': '\u{1F47A}',
- // sailboat, http://emojipedia.org/unicode-5.2/
- 5.2: '\u{26F5}',
- // mahjong, http://emojipedia.org/unicode-5.1/
- 5.1: '\u{1F004}',
- // gear, http://emojipedia.org/unicode-4.1/
- 4.1: '\u{2699}',
- // zap, http://emojipedia.org/unicode-4.0/
- '4.0': '\u{26A1}',
- // recycle, http://emojipedia.org/unicode-3.2/
- 3.2: '\u{267B}',
- // information_source, http://emojipedia.org/unicode-3.0/
- '3.0': '\u{2139}',
- // heart, http://emojipedia.org/unicode-1.1/
- 1.1: '\u{2764}',
-};
-
-function checkPixelInImageDataArray(pixelOffset, imageDataArray) {
- // `4 *` because RGBA
- const indexOffset = 4 * pixelOffset;
- const hasColor = imageDataArray[indexOffset + 0] ||
- imageDataArray[indexOffset + 1] ||
- imageDataArray[indexOffset + 2];
- const isVisible = imageDataArray[indexOffset + 3];
- // Check for some sort of color other than black
- if (hasColor && isVisible) {
- return true;
- }
- return false;
-}
-
-const chromeMatches = navigator.userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\./);
-const isChrome = chromeMatches && chromeMatches.length > 0;
-const chromeVersion = chromeMatches && chromeMatches[1] && parseInt(chromeMatches[1], 10);
-
-// We use 16px because mobile Safari (iOS 9.3) doesn't properly scale emojis :/
-// See 32px, https://i.imgur.com/htY6Zym.png
-// See 16px, https://i.imgur.com/FPPsIF8.png
-const fontSize = 16;
-function generateUnicodeSupportMap(testMap) {
- const testMapKeys = Object.keys(testMap);
- const numTestEntries = testMapKeys
- .reduce((list, testKey) => list.concat(testMap[testKey]), []).length;
-
- const canvas = document.createElement('canvas');
- (window.gl || window).testEmojiUnicodeSupportMapCanvas = canvas;
- const ctx = canvas.getContext('2d');
- canvas.width = (2 * fontSize);
- canvas.height = (numTestEntries * fontSize);
- ctx.fillStyle = '#000000';
- ctx.textBaseline = 'middle';
- ctx.font = `${fontSize}px "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`;
- // Write each emoji to the canvas vertically
- let writeIndex = 0;
- testMapKeys.forEach((testKey) => {
- const testEntry = testMap[testKey];
- [].concat(testEntry).forEach((emojiUnicode) => {
- ctx.fillText(emojiUnicode, 0, (writeIndex * fontSize) + (fontSize / 2));
- writeIndex += 1;
- });
- });
-
- // Read from the canvas
- const resultMap = {};
- let readIndex = 0;
- testMapKeys.forEach((testKey) => {
- const testEntry = testMap[testKey];
- // This needs to be a `reduce` instead of `every` because we need to
- // keep the `readIndex` in sync from the writes by running all entries
- const isTestSatisfied = [].concat(testEntry).reduce((isSatisfied) => {
- // Sample along the vertical-middle for a couple of characters
- const imageData = ctx.getImageData(
- 0,
- (readIndex * fontSize) + (fontSize / 2),
- 2 * fontSize,
- 1,
- ).data;
-
- let isValidEmoji = false;
- for (let currentPixel = 0; currentPixel < 64; currentPixel += 1) {
- const isLookingAtFirstChar = currentPixel < fontSize;
- const isLookingAtSecondChar = currentPixel >= (fontSize + (fontSize / 2));
- // Check for the emoji somewhere along the row
- if (isLookingAtFirstChar && checkPixelInImageDataArray(currentPixel, imageData)) {
- isValidEmoji = true;
-
- // Check to see that nothing is rendered next to the first character
- // to ensure that the ZWJ sequence rendered as one piece
- } else if (isLookingAtSecondChar && checkPixelInImageDataArray(currentPixel, imageData)) {
- isValidEmoji = false;
- break;
- }
- }
-
- readIndex += 1;
- return isSatisfied && isValidEmoji;
- }, true);
-
- resultMap[testKey] = isTestSatisfied;
- });
-
- resultMap.meta = {
- isChrome,
- chromeVersion,
- };
-
- return resultMap;
-}
-
-function getUnicodeSupportMap() {
- let unicodeSupportMap;
- let userAgentFromCache;
-
- const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
-
- if (isLocalStorageAvailable) 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);
-
- if (isLocalStorageAvailable) {
- window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
- window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
- }
- }
-
- return unicodeSupportMap;
-}
-
-export {
- getUnicodeSupportMap,
- generateUnicodeSupportMap,
-};