[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/magicoflolis/Userscript-Plus/userscript/src/js/querySelector.js [Back]  [Original]

'use strict';

const SafeAnimationFrame = class {
  constructor(callback) {
    this.fid = this.tid = undefined;
    this.callback = callback;
  }
  start(delay) {
    if (delay === undefined) {
      if (this.fid === undefined) {
        this.fid = requestAnimationFrame(() => {
          this.onRAF();
        });
      }
      if (this.tid === undefined) {
        this.tid = setTimeout(() => {
          this.onSTO();
        }, 20000);
      }
      return;
    }
    if (this.fid === undefined && this.tid === undefined) {
      this.tid = setTimeout(() => {
        this.macroToMicro();
      }, delay);
    }
  }
  clear() {
    if (this.fid !== undefined) {
      cancelAnimationFrame(this.fid);
      this.fid = undefined;
    }
    if (this.tid !== undefined) {
      clearTimeout(this.tid);
      this.tid = undefined;
    }
  }
  macroToMicro() {
    this.tid = undefined;
    this.start();
  }
  onRAF() {
    if (this.tid !== undefined) {
      clearTimeout(this.tid);
      this.tid = undefined;
    }
    this.fid = undefined;
    this.callback();
  }
  onSTO() {
    if (this.fid !== undefined) {
      cancelAnimationFrame(this.fid);
      this.fid = undefined;
    }
    this.tid = undefined;
    this.callback();
  }
};
/**
 * Object is typeof `Element`
 * @template O
 * @param { O } obj
 * @returns { boolean }
 */
const isElem = (obj) => {
  /** @type { string } */
  const s = Object.prototype.toString.call(obj);
  return s.includes('Element');
};
/**
 * @template T
 * @param { T } target
 * @param { boolean } toQuery
 * @param { Element | Document | undefined } root
 * @returns { T[] }
 */
const normalizeTarget = (target, toQuery = true, root) => {
  if (Object.is(target, null) || Object.is(target, undefined)) {
    return [];
  }
  if (Array.isArray(target)) {
    return target;
  }
  if (typeof target === 'string') {
    return toQuery ? Array.from((root || document).querySelectorAll(target)) : [target];
  }
  if (isElem(target)) {
    return [target];
  }
  return Array.from(target);
};

const makeEventHandler = (selector, callback) => {
  return function (event) {
    const dispatcher = event.currentTarget;
    if (
      dispatcher instanceof HTMLElement === false ||
      typeof dispatcher.querySelectorAll !== 'function'
    ) {
      return;
    }
    const receiver = event.target;
    const ancestor = receiver.closest(selector);
    if (ancestor === receiver && ancestor !== dispatcher && dispatcher.contains(ancestor)) {
      callback.call(receiver, event);
    }
  };
};

class dom {
  static attr(target, attr, value = undefined) {
    for (const elem of normalizeTarget(target)) {
      if (value === undefined) {
        return elem.getAttribute(attr);
      }
      if (value === null) {
        elem.removeAttribute(attr);
      } else {
        elem.setAttribute(attr, value);
      }
    }
  }

  static clone(target) {
    return normalizeTarget(target)[0].cloneNode(true);
  }

  static create(a) {
    if (typeof a === 'string') {
      return document.createElement(a);
    }
  }

  /**
   * @template { HTMLElement } T
   * @param { T } target
   * @param { string } prop
   * @param { * } [value=undefined]
   * @returns { keyof T | void }
   */
  static prop(target, prop, value = undefined) {
    for (const elem of normalizeTarget(target)) {
      if (value === undefined) {
        return elem[prop];
      }
      elem[prop] = value;
    }
  }

  static text(target, text) {
    const targets = normalizeTarget(target);
    if (text === undefined) {
      return targets.length !== 0 ? targets[0].textContent : undefined;
    }
    for (const elem of targets) {
      elem.textContent = text;
    }
  }

  static remove(target) {
    for (const elem of normalizeTarget(target)) {
      elem.remove();
    }
  }

  // target, type, callback, [options]
  // target, type, subtarget, callback, [options]

  static on(target, type, subtarget, callback, options) {
    if (typeof subtarget === 'function') {
      options = callback;
      callback = subtarget;
      subtarget = undefined;
      if (typeof options === 'boolean') {
        options = { capture: true };
      }
    } else {
      callback = makeEventHandler(subtarget, callback);
      if (options === undefined || typeof options === 'boolean') {
        options = { capture: true };
      } else {
        options.capture = true;
      }
    }
    const targets =
      target instanceof Window || target instanceof Document ? [target] : normalizeTarget(target);
    for (const elem of targets) {
      elem.addEventListener(type, callback, options);
    }
  }

  static off(target, type, callback, options) {
    if (typeof callback !== 'function') {
      return;
    }
    if (typeof options === 'boolean') {
      options = { capture: true };
    }
    const targets =
      target instanceof Window || target instanceof Document ? [target] : normalizeTarget(target);
    for (const elem of targets) {
      elem.removeEventListener(type, callback, options);
    }
  }

  static click(target) {
    for (const elem of normalizeTarget(target)) {
      elem.dispatchEvent(new MouseEvent('click'));
    }
  }
}

dom.cl = class {
  static add(target, name) {
    if (Array.isArray(name)) {
      for (const elem of normalizeTarget(target)) {
        elem.classList.add(...name);
      }
    } else {
      for (const elem of normalizeTarget(target)) {
        elem.classList.add(name);
      }
    }
  }

  static remove(target, name) {
    if (Array.isArray(name)) {
      for (const elem of normalizeTarget(target)) {
        elem.classList.remove(...name);
      }
    } else {
      for (const elem of normalizeTarget(target)) {
        elem.classList.remove(name);
      }
    }
  }

  static toggle(target, name, state) {
    let r;
    for (const elem of normalizeTarget(target)) {
      r = elem.classList.toggle(name, state);
    }
    return r;
  }

  static has(target, name) {
    for (const elem of normalizeTarget(target)) {
      if (elem.classList.contains(name)) {
        return true;
      }
    }
    return false;
  }
};

/******************************************************************************/

/**
 * @type { import("../typings/UserJS.d.ts").qsA }
 */
const qsA = (selectors, root) => {
  try {
    return (root || document).querySelectorAll(selectors);
  } catch (ex) {
    console.error(ex);
  }
  return [];
};
/**
 * @type { import("../typings/UserJS.d.ts").qs }
 */
const qs = (selector, root) => {
  try {
    return (root || document).querySelector(selector);
  } catch (ex) {
    console.error(ex);
  }
  return null;
};
/**
 * Prefix for `document.querySelector()` w/ Promise
 * @template { Element } E
 * @param { string } selector - Element for query selection
 * @param { E } root - Root selector Element
 * @returns { Promise }
 */
const query = async (selector, root) => {
  let el = null;
  try {
    el = root || document;
    while (el.querySelector(selector) === null) {
      // await new Promise((resolve) => requestAnimationFrame(resolve));
      await new Promise((resolve) => {
        const queryTimer = new SafeAnimationFrame(resolve);
        queryTimer.start(1);
      });
    }
    return el.querySelector(selector);
  } catch (ex) {
    console.error(ex);
  }
  return el;
};

export { dom, normalizeTarget, qs, qsA, query, SafeAnimationFrame };

Web Proxy Viewer  |  New URL  |  Original Page