import _ from 'underscore'; import createFlash from '~/flash'; import { s__ } from '~/locale'; import emojiAliases from 'emojis/aliases.json'; import axios from '../lib/utils/axios_utils'; import csrf from '../lib/utils/csrf'; import AccessorUtilities from '../lib/utils/accessor'; let emojiMap = null; let validEmojiNames = null; export const EMOJI_VERSION = '1'; const EMOJI_VERSION_LOCALSTORAGE = `EMOJIS_${EMOJI_VERSION}`; const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); export function initEmojiMap() { return new Promise((resolve, reject) => { if (emojiMap) { resolve(emojiMap); } else if (isLocalStorageAvailable && window.localStorage.getItem(EMOJI_VERSION_LOCALSTORAGE)) { emojiMap = JSON.parse(window.localStorage.getItem(EMOJI_VERSION_LOCALSTORAGE)); validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)]; resolve(emojiMap); } else { // We load the JSON from server const axiosInstance = axios.create(); // If the static JSON file is on a CDN we don't want to send the default CSRF token if (gon.asset_host) { delete axiosInstance.defaults.headers.common[csrf.headerKey]; } axiosInstance .get(`${gon.relative_url_root || ''}/-/emojis/${EMOJI_VERSION}/emojis.json`) .then(({ data }) => { emojiMap = data; validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)]; resolve(emojiMap); if (isLocalStorageAvailable) { window.localStorage.setItem(EMOJI_VERSION_LOCALSTORAGE, JSON.stringify(emojiMap)); } }) .catch(err => { createFlash(s__('Emojis|Something went wrong while loading emojis.')); reject(err); }); } }); } export function normalizeEmojiName(name) { return Object.prototype.hasOwnProperty.call(emojiAliases, name) ? emojiAliases[name] : name; } export function getValidEmojiNames() { return validEmojiNames; } export function isEmojiNameValid(name) { return validEmojiNames.indexOf(name) >= 0; } export function filterEmojiNames(filter) { const match = filter.toLowerCase(); return validEmojiNames.filter(name => name.indexOf(match) >= 0); } export function filterEmojiNamesByAlias(filter) { return _.uniq(filterEmojiNames(filter).map(name => normalizeEmojiName(name))); } let emojiCategoryMap; export function getEmojiCategoryMap() { if (!emojiCategoryMap) { emojiCategoryMap = { activity: [], people: [], nature: [], food: [], travel: [], objects: [], symbols: [], flags: [], }; Object.keys(emojiMap).forEach(name => { const emoji = emojiMap[name]; if (emojiCategoryMap[emoji.c]) { emojiCategoryMap[emoji.c].push(name); } }); } return emojiCategoryMap; } export function getEmojiInfo(query) { let name = normalizeEmojiName(query); let emojiInfo = emojiMap[name]; // Fallback to question mark for unknown emojis if (!emojiInfo) { name = 'grey_question'; emojiInfo = emojiMap[name]; } return { ...emojiInfo, name }; } export function emojiFallbackImageSrc(inputName) { const { name } = getEmojiInfo(inputName); return `${gon.asset_host || ''}${gon.relative_url_root || ''}/-/emojis/${EMOJI_VERSION}/${name}.png`; } export function emojiImageTag(name, src) { return `:${name}:`; } export function glEmojiTag(inputName, options) { const opts = { sprite: false, forceFallback: false, ...options }; const name = normalizeEmojiName(inputName); const fallbackSpriteClass = `emoji-${name}`; const classList = []; if (opts.forceFallback && opts.sprite) { classList.push('emoji-icon'); classList.push(fallbackSpriteClass); } const classAttribute = classList.length > 0 ? `class="${classList.join(' ')}"` : ''; const fallbackSpriteAttribute = opts.sprite ? `data-fallback-sprite-class="${fallbackSpriteClass}"` : ''; const forceFallbackAttribute = opts.forceFallback ? 'data-force-fallback="true"' : ''; return ` `; }