You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

55 lines
2.5 KiB

  1. import emojione from 'emojione';
  2. import Trie from 'substring-trie';
  3. const mappedUnicode = emojione.mapUnicodeToShort();
  4. const trie = new Trie(Object.keys(emojione.jsEscapeMap));
  5. function emojify(str) {
  6. // This walks through the string from start to end, ignoring any tags (<p>, <br>, etc.)
  7. // and replacing valid shortnames like :smile: and :wink: as well as unicode strings
  8. // that _aren't_ within tags with an <img> version.
  9. // The goal is to be the same as an emojione.regShortNames/regUnicode replacement, but faster.
  10. let i = -1;
  11. let insideTag = false;
  12. let insideShortname = false;
  13. let shortnameStartIndex = -1;
  14. let match;
  15. while (++i < str.length) {
  16. const char = str.charAt(i);
  17. if (insideShortname && char === ':') {
  18. const shortname = str.substring(shortnameStartIndex, i + 1);
  19. if (shortname in emojione.emojioneList) {
  20. const unicode = emojione.emojioneList[shortname].unicode[emojione.emojioneList[shortname].unicode.length - 1];
  21. const alt = emojione.convert(unicode.toUpperCase());
  22. const replacement = `<img draggable="false" class="emojione" alt="${alt}" title="${shortname}" src="/emoji/${unicode}.svg" />`;
  23. str = str.substring(0, shortnameStartIndex) + replacement + str.substring(i + 1);
  24. i += (replacement.length - shortname.length - 1); // jump ahead the length we've added to the string
  25. } else {
  26. i--; // stray colon, try again
  27. }
  28. insideShortname = false;
  29. } else if (insideTag && char === '>') {
  30. insideTag = false;
  31. } else if (char === '<') {
  32. insideTag = true;
  33. insideShortname = false;
  34. } else if (!insideTag && char === ':') {
  35. insideShortname = true;
  36. shortnameStartIndex = i;
  37. } else if (!insideTag && (match = trie.search(str.substring(i)))) {
  38. const unicodeStr = match;
  39. if (unicodeStr in emojione.jsEscapeMap) {
  40. const unicode = emojione.jsEscapeMap[unicodeStr];
  41. const short = mappedUnicode[unicode];
  42. const filename = emojione.emojioneList[short].fname;
  43. const alt = emojione.convert(unicode.toUpperCase());
  44. const replacement = `<img draggable="false" class="emojione" alt="${alt}" title="${short}" src="/emoji/${filename}.svg" />`;
  45. str = str.substring(0, i) + replacement + str.substring(i + unicodeStr.length);
  46. i += (replacement.length - unicodeStr.length); // jump ahead the length we've added to the string
  47. }
  48. }
  49. }
  50. return str;
  51. }
  52. export default emojify;