BigW Consortium Gitlab

gl_emoji.js 3.37 KB
import installCustomElements from 'document-register-element';
import { emojiMap, normalizeEmojiName, isEmojiUnicodeSupported, getUnicodeSupportMap } from '../emoji';

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" />`;
}

function assembleFallbackImageSrc(inputName) {
  let name = normalizeEmojiName(inputName);
  let emojiInfo = emojiMap[name];
  // Fallback to question mark for unknown emojis
  if (!emojiInfo) {
    name = 'grey_question';
    emojiInfo = emojiMap[name];
  }
  const fallbackImageSrc = `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/emoji/${name}-${emojiInfo.digest}.png`;

  return fallbackImageSrc;
}

function glEmojiTag(inputName, options) {
  const opts = { sprite: false, forceFallback: false, ...options };
  let name = normalizeEmojiName(inputName);
  let emojiInfo = emojiMap[name];
  // Fallback to question mark for unknown emojis
  if (!emojiInfo) {
    name = 'grey_question';
    emojiInfo = emojiMap[name];
  }

  const fallbackImageSrc = assembleFallbackImageSrc(name);
  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}"` : '';
  let contents = emojiInfo.moji;
  if (opts.forceFallback && !opts.sprite) {
    contents = emojiImageTag(name, fallbackImageSrc);
  }

  return `
  <gl-emoji
    ${classAttribute}
    data-name="${name}"
    data-fallback-src="${fallbackImageSrc}"
    ${fallbackSpriteAttribute}
    data-unicode-version="${emojiInfo.unicodeVersion}"
    title="${emojiInfo.description}"
  >
    ${contents}
  </gl-emoji>
  `;
}

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 (
      emojiUnicode &&
      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,
  });
}

export {
  installGlEmojiElement,
  glEmojiTag,
  emojiImageTag,
};