UserUtils

Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more

目前為 2023-09-07 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/472956/1246851/UserUtils.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         UserUtils
// @description  Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more 
// @namespace    https://github.com/Sv443-Network/UserUtils
// @version      0.5.3
// @license      MIT
// @author       Sv443
// @copyright    Sv443 (https://github.com/Sv443)
// @supportURL   https://github.com/Sv443-Network/UserUtils/issues
// @homepageURL  https://github.com/Sv443-Network/UserUtils#readme
// ==/UserScript==

var UserUtils = (function (exports) {
  var __defProp = Object.defineProperty;
  var __defProps = Object.defineProperties;
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __spreadValues = (a, b) => {
    for (var prop in b || (b = {}))
      if (__hasOwnProp.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    if (__getOwnPropSymbols)
      for (var prop of __getOwnPropSymbols(b)) {
        if (__propIsEnum.call(b, prop))
          __defNormalProp(a, prop, b[prop]);
      }
    return a;
  };
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
  var __async = (__this, __arguments, generator) => {
    return new Promise((resolve, reject) => {
      var fulfilled = (value) => {
        try {
          step(generator.next(value));
        } catch (e) {
          reject(e);
        }
      };
      var rejected = (value) => {
        try {
          step(generator.throw(value));
        } catch (e) {
          reject(e);
        }
      };
      var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
      step((generator = generator.apply(__this, __arguments)).next());
    });
  };

  // lib/math.ts
  function clamp(value, min, max) {
    return Math.max(Math.min(value, max), min);
  }
  function mapRange(value, range_1_min, range_1_max, range_2_min, range_2_max) {
    if (Number(range_1_min) === 0 && Number(range_2_min) === 0)
      return value * (range_2_max / range_1_max);
    return (value - range_1_min) * ((range_2_max - range_2_min) / (range_1_max - range_1_min)) + range_2_min;
  }
  function randRange(...args) {
    let min, max;
    if (typeof args[0] === "number" && typeof args[1] === "number") {
      [min, max] = args;
    } else if (typeof args[0] === "number" && typeof args[1] !== "number") {
      min = 0;
      max = args[0];
    } else
      throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof args[0]}" and "${typeof args[1]}"`);
    min = Number(min);
    max = Number(max);
    if (isNaN(min) || isNaN(max))
      throw new TypeError(`Parameters "min" and "max" can't be NaN`);
    if (min > max)
      throw new TypeError(`Parameter "min" can't be bigger than "max"`);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  // lib/array.ts
  function randomItem(array) {
    return randomItemIndex(array)[0];
  }
  function randomItemIndex(array) {
    if (array.length === 0)
      return [void 0, void 0];
    const idx = randRange(array.length - 1);
    return [array[idx], idx];
  }
  function takeRandomItem(arr) {
    const [itm, idx] = randomItemIndex(arr);
    if (idx === void 0)
      return void 0;
    arr.splice(idx, 1);
    return itm;
  }
  function randomizeArray(array) {
    const retArray = [...array];
    if (array.length === 0)
      return array;
    for (let i = retArray.length - 1; i > 0; i--) {
      const j = Math.floor(randRange(0, 1e4) / 1e4 * (i + 1));
      [retArray[i], retArray[j]] = [retArray[j], retArray[i]];
    }
    return retArray;
  }

  // lib/dom.ts
  function getUnsafeWindow() {
    try {
      return unsafeWindow;
    } catch (e) {
      return window;
    }
  }
  function insertAfter(beforeElement, afterElement) {
    var _a;
    (_a = beforeElement.parentNode) == null ? void 0 : _a.insertBefore(afterElement, beforeElement.nextSibling);
    return afterElement;
  }
  function addParent(element2, newParent) {
    const oldParent = element2.parentNode;
    if (!oldParent)
      throw new Error("Element doesn't have a parent node");
    oldParent.replaceChild(newParent, element2);
    newParent.appendChild(element2);
    return newParent;
  }
  function addGlobalStyle(style) {
    const styleElem = document.createElement("style");
    styleElem.innerHTML = style;
    document.head.appendChild(styleElem);
  }
  function preloadImages(srcUrls, rejects = false) {
    const promises = srcUrls.map((src) => new Promise((res, rej) => {
      const image = new Image();
      image.src = src;
      image.addEventListener("load", () => res(image));
      image.addEventListener("error", (evt) => rejects && rej(evt));
    }));
    return Promise.allSettled(promises);
  }
  function openInNewTab(href) {
    const openElem = document.createElement("a");
    Object.assign(openElem, {
      className: "userutils-open-in-new-tab",
      target: "_blank",
      rel: "noopener noreferrer",
      href
    });
    openElem.style.display = "none";
    document.body.appendChild(openElem);
    openElem.click();
    setTimeout(openElem.remove, 50);
  }
  function interceptEvent(eventObject, eventName, predicate) {
    if (typeof Error.stackTraceLimit === "number" && Error.stackTraceLimit < 1e3) {
      Error.stackTraceLimit = 1e3;
    }
    (function(original) {
      element.__proto__.addEventListener = function(...args) {
        if (args[0] === eventName && predicate())
          return;
        else
          return original.apply(this, args);
      };
    })(eventObject.__proto__.addEventListener);
  }
  function interceptWindowEvent(eventName, predicate) {
    return interceptEvent(getUnsafeWindow(), eventName, predicate);
  }
  function amplifyMedia(mediaElement, multiplier = 1) {
    const context = new (window.AudioContext || window.webkitAudioContext)();
    const result = {
      mediaElement,
      amplify: (multiplier2) => {
        result.gain.gain.value = multiplier2;
      },
      getAmpLevel: () => result.gain.gain.value,
      context,
      source: context.createMediaElementSource(mediaElement),
      gain: context.createGain()
    };
    result.source.connect(result.gain);
    result.gain.connect(context.destination);
    result.amplify(multiplier);
    return result;
  }

  // lib/misc.ts
  function autoPlural(word, num) {
    if (Array.isArray(num) || num instanceof NodeList)
      num = num.length;
    return `${word}${num === 1 ? "" : "s"}`;
  }
  function pauseFor(time) {
    return new Promise((res) => {
      setTimeout(() => res(), time);
    });
  }
  function debounce(func, timeout = 300) {
    let timer;
    return function(...args) {
      clearTimeout(timer);
      timer = setTimeout(() => func.apply(this, args), timeout);
    };
  }
  function fetchAdvanced(_0) {
    return __async(this, arguments, function* (url, options = {}) {
      const { timeout = 1e4 } = options;
      const controller = new AbortController();
      const id = setTimeout(() => controller.abort(), timeout);
      const res = yield fetch(url, __spreadProps(__spreadValues({}, options), {
        signal: controller.signal
      }));
      clearTimeout(id);
      return res;
    });
  }

  // lib/onSelector.ts
  var selectorMap = /* @__PURE__ */ new Map();
  function onSelector(selector, options) {
    let selectorMapItems = [];
    if (selectorMap.has(selector))
      selectorMapItems = selectorMap.get(selector);
    selectorMapItems.push(options);
    selectorMap.set(selector, selectorMapItems);
    checkSelectorExists(selector, selectorMapItems);
  }
  function removeOnSelector(selector) {
    return selectorMap.delete(selector);
  }
  function checkSelectorExists(selector, options) {
    const deleteIndices = [];
    options.forEach((option, i) => {
      try {
        const elements = option.all ? document.querySelectorAll(selector) : document.querySelector(selector);
        if (elements !== null && elements instanceof NodeList && elements.length > 0 || elements !== null) {
          option.listener(elements);
          if (!option.continuous)
            deleteIndices.push(i);
        }
      } catch (err) {
        console.error(`Couldn't call listener for selector '${selector}'`, err);
      }
    });
    if (deleteIndices.length > 0) {
      const newOptsArray = options.filter((_, i) => !deleteIndices.includes(i));
      if (newOptsArray.length === 0)
        selectorMap.delete(selector);
      else {
        selectorMap.set(selector, newOptsArray);
      }
    }
  }
  function initOnSelector(options = {}) {
    const observer = new MutationObserver(() => {
      for (const [selector, options2] of selectorMap.entries())
        checkSelectorExists(selector, options2);
    });
    observer.observe(document.body, __spreadValues({
      subtree: true,
      childList: true
    }, options));
  }
  function getSelectorMap() {
    return selectorMap;
  }

  exports.addGlobalStyle = addGlobalStyle;
  exports.addParent = addParent;
  exports.amplifyMedia = amplifyMedia;
  exports.autoPlural = autoPlural;
  exports.clamp = clamp;
  exports.debounce = debounce;
  exports.fetchAdvanced = fetchAdvanced;
  exports.getSelectorMap = getSelectorMap;
  exports.getUnsafeWindow = getUnsafeWindow;
  exports.initOnSelector = initOnSelector;
  exports.insertAfter = insertAfter;
  exports.interceptEvent = interceptEvent;
  exports.interceptWindowEvent = interceptWindowEvent;
  exports.mapRange = mapRange;
  exports.onSelector = onSelector;
  exports.openInNewTab = openInNewTab;
  exports.pauseFor = pauseFor;
  exports.preloadImages = preloadImages;
  exports.randRange = randRange;
  exports.randomItem = randomItem;
  exports.randomItemIndex = randomItemIndex;
  exports.randomizeArray = randomizeArray;
  exports.removeOnSelector = removeOnSelector;
  exports.takeRandomItem = takeRandomItem;

  return exports;

})({});