summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/emoji/index.js
blob: 4567c807c40597dfd2c21ddf126778ea4db27373 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { uniq } from 'lodash';
import emojiAliases from 'emojis/aliases.json';
import axios from '../lib/utils/axios_utils';

import AccessorUtilities from '../lib/utils/accessor';

let emojiMap = null;
let emojiPromise = null;
let validEmojiNames = null;

export const EMOJI_VERSION = '1';

const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();

export function initEmojiMap() {
  emojiPromise =
    emojiPromise ||
    new Promise((resolve, reject) => {
      if (emojiMap) {
        resolve(emojiMap);
      } else if (
        isLocalStorageAvailable &&
        window.localStorage.getItem('gl-emoji-map-version') === EMOJI_VERSION &&
        window.localStorage.getItem('gl-emoji-map')
      ) {
        emojiMap = JSON.parse(window.localStorage.getItem('gl-emoji-map'));
        validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)];
        resolve(emojiMap);
      } else {
        // We load the JSON file direct from the server
        // because it can't be loaded from a CDN due to
        // cross domain problems with JSON
        axios
          .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('gl-emoji-map-version', EMOJI_VERSION);
              window.localStorage.setItem('gl-emoji-map', JSON.stringify(emojiMap));
            }
          })
          .catch(err => {
            reject(err);
          });
      }
    });

  return emojiPromise;
}

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 `<img class="emoji" title=":${name}:" alt=":${name}:" src="${src}" width="20" height="20" align="absmiddle" />`;
}

export function glEmojiTag(inputName, options) {
  const opts = { sprite: false, ...options };
  const name = normalizeEmojiName(inputName);
  const fallbackSpriteClass = `emoji-${name}`;

  const fallbackSpriteAttribute = opts.sprite
    ? `data-fallback-sprite-class="${fallbackSpriteClass}"`
    : '';

  return `
    <gl-emoji
      ${fallbackSpriteAttribute}
      data-name="${name}"></gl-emoji>
  `;
}