Greasy Fork is available in English.

AsyncUI Class

UI utility class

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/476649/1259544/AsyncUI%20Class.js

// ==UserScript==
// @name         AsyncUI Class
// @version      1.0.0
// @description  UI utility class
// @author       Paweł Malak (pawemala) LCJ2
// @license      MIT
// ==/UserScript==

class AsyncUI {
  /**
   * Wait for an element with a given selector to be available
   * @param {string} selector CSS selector of an element
   * @returns {Promise<HTMLElement>}
   */
  static waitForElement(selector) {
    return new Promise(resolve => {
      if (document.querySelector(selector)) {
        return resolve(document.querySelector(selector));
      }

      const observer = new MutationObserver(() => {
        if (document.querySelector(selector)) {
          resolve(document.querySelector(selector));
          observer.disconnect();
        }
      });

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

  /**
   * Wait n seconds for an element. Return element if exists or null if not
   * @param {string} selector CSS selector of an element
   * @param {number} timeout Time to wait for element in seconds
   * @returns {Promise<HTMLElement | null>} Element if exists or null if not
   */
  static timeForElement(selector, timeout = 10) {
    return new Promise(resolve => {
      if (document.querySelector(selector)) {
        return resolve(document.querySelector(selector));
      }

      const startTime = Date.now();
      timeout *= 1000;

      const wait = setInterval(() => {
        if (document.querySelector(selector)) {
          window.clearInterval(wait);
          return resolve(document.querySelector(selector));
        }

        if (Date.now() - startTime > timeout) {
          window.clearInterval(wait);
          return resolve(null);
        }
      }, 1000);
    });
  }

  /**
   * Watch element and execute callback function on change
   * @param {string} selector CSS selector of an element
   * @param {Function} callback Function to be called upon change detection
   * @returns {MutationObserver} Observer object to disconnect when it's no longer needed
   */
  static watchForChanges(selector, callback) {
    if (!document.querySelector(selector)) {
      throw new Error(`${selector} was not found`);
    }

    const observer = new MutationObserver(callback);

    observer.observe(document.querySelector(selector), {
      attributes: true,
      childList: true,
      subtree: true
    });

    return observer;
  }

  /**
   * Inject custom CSS styles at the bottom of <head> element
   * @param {string} style Custom CSS string to be injected
   */
  static injectStyle(style) {
    const customStyleEl = document.createElement('style');
    customStyleEl.textContent = style;
    document.head.appendChild(customStyleEl);
  }
}