Node Mutation Hook Library

A small wrapper around MutationObserver to hook into creation of elements (filtered on CSS selector) or removal of nodes.

이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greasyfork.org/scripts/565361/1755404/Node%20Mutation%20Hook%20Library.js을(를) 사용하여 포함하는 라이브러리입니다.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Node Mutation Hook Library
// @namespace   https://greasyfork.org/users/1545341
// @version     2.1.0
// @license     MIT
// @author      abcenjoyer
// @description A small wrapper around MutationObserver to hook into creation of elements (filtered on CSS selector) or removal of nodes.
// ==/UserScript==

function hookCreation(selector, callback) {
  const observer = new MutationObserver((mutations) => {
    for (const record of mutations) {
      for (const node of record.addedNodes) {
        if (node.nodeType === Node.ELEMENT_NODE) {
          if (node.matches(selector)) {
            callback(node, observer);
          }

          for (const element of node.querySelectorAll(selector)) {
            callback(element, observer);
          }
        }
      }
    }
  });

  observer.observe(document.documentElement, {
    childList: true,
    subtree: true
  });
}

function hookRemoval(targetNode, callback) {
  const observer = new MutationObserver((mutations) => {
    for (const record of mutations) {
      for (const node of record.removedNodes) {
          if (node.contains(targetNode)) {
            observer.disconnect();
            callback();
          }
      }
    }
  });

  // observing the entire document is required because if targetNode is deleted because an ancestor node was, observing the parent won't work
  observer.observe(document, {
    childList: true,
    subtree: true
  });
}