Nomoji

Blocks all emojis except for flags from being displayed on any website.

// ==UserScript==
// @name        Nomoji
// @match       *://*/*
// @run-at      document-start
// @grant       none
// @version 0.0.1.20250801002619
// @namespace https://greasyfork.org/users/1497719
// @description Blocks all emojis except for flags from being displayed on any website.
// ==/UserScript==

(function () {
  const emojiRegex = /(\p{Extended_Pictographic}|\uFE0F)/gu;

  function isEditable(node) {
    let el = node.nodeType === 3 ? node.parentElement : node;
    while (el) {
      if (
        el.nodeName === 'INPUT' ||
        el.nodeName === 'TEXTAREA' ||
        el.isContentEditable
      ) return true;
      el = el.parentElement;
    }
    return false;
  }

  function stripEmojis(root) {
    const walker = document.createTreeWalker(
      root,
      NodeFilter.SHOW_TEXT,
      null,
      false
    );
    let node;
    while ((node = walker.nextNode())) {
      if (!isEditable(node)) {
        node.nodeValue = node.nodeValue.replace(emojiRegex, '');
      }
    }
  }

  const pendingNodes = new Set();
  let scheduled = false;

  function scheduleFlush() {
    if (scheduled) return;
    scheduled = true;
    requestIdleCallback(() => {
      requestAnimationFrame(() => {
        for (const node of pendingNodes) {
          if (node.nodeType === 3 && !isEditable(node)) {
            node.nodeValue = node.nodeValue.replace(emojiRegex, '');
          } else if (node.nodeType === 1 && !isEditable(node)) {
            stripEmojis(node);
          }
        }
        pendingNodes.clear();
        scheduled = false;
      });
    });
  }

  function observe() {
    new MutationObserver(mutations => {
      for (const { addedNodes, type, target } of mutations) {
        addedNodes.forEach(n => {
          if (n.nodeType === 3 || n.nodeType === 1) {
            pendingNodes.add(n);
          }
        });
      }
      scheduleFlush();
    }).observe(document.body, {
      childList: true,
      subtree: true,
      characterData: true,
    });
  }

  function tryInit() {
    if (!document.body) {
      requestAnimationFrame(tryInit);
      return;
    }
    stripEmojis(document.body);
    observe();
  }

  tryInit();
})();