onElementReady

detect when an element is ready

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greasyfork.org/scripts/419640/1776135/onElementReady.js

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         onElementReady
// @namespace    https://zachhardesty.com
// @exclude      *
// @homepage     https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/utils/onElementReady.js
// @homepageURL  https://github.com/zachhardesty7/tamper-monkey-scripts-collection/raw/master/utils/onElementReady.js
// @license      GPL-3.0-only; http://www.gnu.org/licenses/gpl-3.0.txt
// @copyright    2026, Zach Hardesty (https://zachhardesty.com/)
// @version      0.10.2

// @description  Detect any new DOM Element by its CSS Selector, then trigger a function. Includes Promise & Callback interface. Based on ES6 MutationObserver. Ships legacy waitForKeyElements interface, too.
// @author       Zach Hardesty <[email protected]> (https://github.com/zachhardesty7)
// ==/UserScript==

// ORIGINAL CODE BY sidneys: https://gist.github.com/sidneys/ee7a6b80315148ad1fb6847e72a22313

// Remember already found elements via this attribute
const QUERIED_ATTRIBUTE_NAME = "was-queried"

const DEFAULT_OPTIONS = /** @type {const} @satisfies {OnElementReadyOptions} */ ({
  findFirst: false,
  findOnce: true,
  root: document,
})

/**
 * Internal function used by {@link onElementReady} to query for new DOM nodes matching a
 * specified selector.
 *
 * @private
 * @param {string} selector
 * @param {OnElementReadyOptions} options
 * @param {OnElementReadyCallback} callback
 */
// eslint-disable-next-line prefer-const
let queryForElements = (selector, options, callback) => {
  const finalOptions = { ...DEFAULT_OPTIONS, ...options }

  // Search for elements by selector
  const elementList = finalOptions.root?.querySelectorAll(selector) || []
  for (const element of elementList) {
    if (element.hasAttribute(QUERIED_ATTRIBUTE_NAME)) {
      continue
    }

    element.setAttribute(QUERIED_ATTRIBUTE_NAME, "true")
    callback(element)

    // run reset after 2 seconds
    if (!finalOptions.findOnce) {
      setTimeout(() => {
        element.removeAttribute(QUERIED_ATTRIBUTE_NAME)
      }, 2000)
    }
  }
}

/**
 * Wait for elements with a given CSS selector to enter the DOM. Returns a `Promise`
 * resolving with found/changed element and triggers a callback for every found/changed
 * element.
 *
 * @param {string} selector
 * @param {OnElementReadyOptions} [options]
 * @param {OnElementReadyCallback} [callback]
 * @returns {OnElementReadyReturn}
 * @public
 */
// eslint-disable-next-line prefer-const
let onElementReady = (selector, options = DEFAULT_OPTIONS, callback = () => {}) => {
  const finalOptions = { ...DEFAULT_OPTIONS, ...options }

  return new Promise((resolve) => {
    // Initial Query
    queryForElements(selector, finalOptions, (element) => {
      resolve(element)
      callback(element)
    })

    // Continuous Query
    const observer = new MutationObserver(() => {
      // DOM Changes detected
      queryForElements(selector, finalOptions, (element) => {
        resolve(element)
        callback(element)

        // stop querying after first successful pass and remove mutation observer,
        // calling multiple times (when mutliple matching elements) seems to work fine
        if (finalOptions.findFirst) {
          observer.disconnect()
        }
      })
    })

    // Observe DOM Changes
    observer.observe(document.documentElement, {
      attributes: false,
      childList: true,
      subtree: true,
    })
  })
}

/**
 * @deprecated
 * @param {string} selector
 * @param {OnElementReadyCallback} [callback]
 * @param {OnElementReadyOptions} [options]
 * @returns {OnElementReadyReturn}
 * @public
 */
// eslint-disable-next-line no-unused-vars, prefer-const
let waitForKeyElements = (selector, callback, options) =>
  onElementReady(selector, options, callback)