[Glitch] Fix emoji substitution not applying only to text nodes in Web UI
Port 625e086996 to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
			
			
This commit is contained in:
		
							parent
							
								
									767630be24
								
							
						
					
					
						commit
						71982e5c83
					
				| 
						 | 
					@ -19,15 +19,23 @@ const emojiFilename = (filename) => {
 | 
				
			||||||
  return borderedEmoji.includes(filename) ? (filename + '_border') : filename;
 | 
					  return borderedEmoji.includes(filename) ? (filename + '_border') : filename;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emojify = (str, customEmojis = {}) => {
 | 
					const emojifyTextNode = (node, customEmojis) => {
 | 
				
			||||||
  const tagCharsWithoutEmojis = '<&';
 | 
					  const parentElement = node.parentElement;
 | 
				
			||||||
  const tagCharsWithEmojis = Object.keys(customEmojis).length ? '<&:' : '<&';
 | 
					  let str = node.textContent;
 | 
				
			||||||
  let rtn = '', tagChars = tagCharsWithEmojis, invisible = 0;
 | 
					
 | 
				
			||||||
  for (;;) {
 | 
					  for (;;) {
 | 
				
			||||||
    let match, i = 0, tag;
 | 
					    let match, i = 0;
 | 
				
			||||||
    while (i < str.length && (tag = tagChars.indexOf(str[i])) === -1 && (invisible || useSystemEmojiFont || !(match = trie.search(str.slice(i))))) {
 | 
					
 | 
				
			||||||
 | 
					    if (customEmojis === null) {
 | 
				
			||||||
 | 
					      while (i < str.length && !(match = trie.search(str.slice(i)))) {
 | 
				
			||||||
        i += str.codePointAt(i) < 65536 ? 1 : 2;
 | 
					        i += str.codePointAt(i) < 65536 ? 1 : 2;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      while (i < str.length && str[i] !== ':' && !(match = trie.search(str.slice(i)))) {
 | 
				
			||||||
 | 
					        i += str.codePointAt(i) < 65536 ? 1 : 2;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let rend, replacement = '';
 | 
					    let rend, replacement = '';
 | 
				
			||||||
    if (i === str.length) {
 | 
					    if (i === str.length) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					@ -35,8 +43,6 @@ const emojify = (str, customEmojis = {}) => {
 | 
				
			||||||
      if (!(() => {
 | 
					      if (!(() => {
 | 
				
			||||||
        rend = str.indexOf(':', i + 1) + 1;
 | 
					        rend = str.indexOf(':', i + 1) + 1;
 | 
				
			||||||
        if (!rend) return false; // no pair of ':'
 | 
					        if (!rend) return false; // no pair of ':'
 | 
				
			||||||
        const lt = str.indexOf('<', i + 1);
 | 
					 | 
				
			||||||
        if (!(lt === -1 || lt >= rend)) return false; // tag appeared before closing ':'
 | 
					 | 
				
			||||||
        const shortname = str.slice(i, rend);
 | 
					        const shortname = str.slice(i, rend);
 | 
				
			||||||
        // now got a replacee as ':shortname:'
 | 
					        // now got a replacee as ':shortname:'
 | 
				
			||||||
        // if you want additional emoji handler, add statements below which set replacement and return true.
 | 
					        // if you want additional emoji handler, add statements below which set replacement and return true.
 | 
				
			||||||
| 
						 | 
					@ -47,29 +53,6 @@ const emojify = (str, customEmojis = {}) => {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
      })()) rend = ++i;
 | 
					      })()) rend = ++i;
 | 
				
			||||||
    } else if (tag >= 0) { // <, &
 | 
					 | 
				
			||||||
      rend = str.indexOf('>;'[tag], i + 1) + 1;
 | 
					 | 
				
			||||||
      if (!rend) {
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (tag === 0) {
 | 
					 | 
				
			||||||
        if (invisible) {
 | 
					 | 
				
			||||||
          if (str[i + 1] === '/') { // closing tag
 | 
					 | 
				
			||||||
            if (!--invisible) {
 | 
					 | 
				
			||||||
              tagChars = tagCharsWithEmojis;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          } else if (str[rend - 2] !== '/') { // opening tag
 | 
					 | 
				
			||||||
            invisible++;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          if (str.startsWith('<span class="invisible">', i)) {
 | 
					 | 
				
			||||||
            // avoid emojifying on invisible text
 | 
					 | 
				
			||||||
            invisible = 1;
 | 
					 | 
				
			||||||
            tagChars = tagCharsWithoutEmojis;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      i = rend;
 | 
					 | 
				
			||||||
    } else if (!useSystemEmojiFont) { // matched to unicode emoji
 | 
					    } else if (!useSystemEmojiFont) { // matched to unicode emoji
 | 
				
			||||||
      const { filename, shortCode } = unicodeMapping[match];
 | 
					      const { filename, shortCode } = unicodeMapping[match];
 | 
				
			||||||
      const title = shortCode ? `:${shortCode}:` : '';
 | 
					      const title = shortCode ? `:${shortCode}:` : '';
 | 
				
			||||||
| 
						 | 
					@ -80,10 +63,39 @@ const emojify = (str, customEmojis = {}) => {
 | 
				
			||||||
        rend += 1;
 | 
					        rend += 1;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    rtn += str.slice(0, i) + replacement;
 | 
					
 | 
				
			||||||
 | 
					    node.textContent = str.slice(0, i);
 | 
				
			||||||
 | 
					    parentElement.insertAdjacentHTML('beforeend', replacement);
 | 
				
			||||||
    str = str.slice(rend);
 | 
					    str = str.slice(rend);
 | 
				
			||||||
 | 
					    node = document.createTextNode(str);
 | 
				
			||||||
 | 
					    parentElement.append(node);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return rtn + str;
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emojifyNode = (node, customEmojis) => {
 | 
				
			||||||
 | 
					  for (const child of node.childNodes) {
 | 
				
			||||||
 | 
					    switch(child.nodeType) {
 | 
				
			||||||
 | 
					    case Node.TEXT_NODE:
 | 
				
			||||||
 | 
					      emojifyTextNode(child, customEmojis);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case Node.ELEMENT_NODE:
 | 
				
			||||||
 | 
					      if (!child.classList.contains('invisible'))
 | 
				
			||||||
 | 
					        emojifyNode(child, customEmojis);
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emojify = (str, customEmojis = {}) => {
 | 
				
			||||||
 | 
					  const wrapper = document.createElement('div');
 | 
				
			||||||
 | 
					  wrapper.innerHTML = str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!Object.keys(customEmojis).length)
 | 
				
			||||||
 | 
					    customEmojis = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  emojifyNode(wrapper, customEmojis);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return wrapper.innerHTML;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default emojify;
 | 
					export default emojify;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue