Mirror of UserUtils' source code https://github.com/Sv443-Network/UserUtils

Sven 0cc19c1ee2 docs: fix amplifyMedia example před 1 rokem
.changeset 5c24fe3612 chore: create new release před 1 rokem
.github fc03613125 ci: pr title & commit msg for releases před 1 rokem
lib d0162ec024 fix: onSelector not triggering & allow all options před 1 rokem
.eslintrc.cjs e54ccbcf24 feat: initial commit před 1 rokem
.gitignore 72181703dd docs: readme stuff před 1 rokem
.npmignore dcfe430eaf fix: update npmignore před 1 rokem
CHANGELOG.md b413d53b46 docs: changelog format před 1 rokem
LICENSE.txt e54ccbcf24 feat: initial commit před 1 rokem
README.md 0cc19c1ee2 docs: fix amplifyMedia example před 1 rokem
package-lock.json 9c9426a111 ref: improve build commands před 1 rokem
package.json 5c24fe3612 chore: create new release před 1 rokem
tsconfig.json 72181703dd docs: readme stuff před 1 rokem

README.md

## UserUtils Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more. Contains builtin TypeScript declarations. Webpack compatible and supports ESM and CJS. If you like using this library, please consider [supporting the development ❤️](https://github.com/sponsors/Sv443)

## Table of Contents: - [**Installation**](#installation) - [**Preamble**](#preamble) - [**License**](#license) - [**Features**](#features) - [DOM:](#dom) - [onSelector()](#onselector) - call a listener once a selector is found in the DOM - [initOnSelector()](#initonselector) - needs to be called once to be able to use `onSelector()` - [getSelectorMap()](#getselectormap) - returns all currently registered selectors, listeners and options - [getUnsafeWindow()](#getunsafewindow) - get the unsafeWindow object or fall back to the regular window object - [insertAfter()](#insertafter) - insert an element as a sibling after another element - [addParent()](#addparent) - add a parent element around another element - [addGlobalStyle()](#addglobalstyle) - add a global style to the page - [preloadImages()](#preloadimages) - preload images into the browser cache for faster loading later on - [openInNewTab()](#openinnewtab) - open a link in a new tab - [interceptEvent()](#interceptevent) - conditionally intercepts events registered by `addEventListener()` on any given EventTarget object - [interceptWindowEvent()](#interceptwindowevent) - conditionally intercepts events registered by `addEventListener()` on the window object - [amplifyMedia()](#amplifymedia) - amplify an audio or video element's volume past the maximum of 100% - [Math:](#math) - [clamp()](#clamp) - constrain a number between a min and max value - [mapRange()](#maprange) - map a number from one range to the same spot in another range - [randRange()](#randrange) - generate a random number between a min and max boundary - [Misc:](#misc) - [autoPlural()](#autoplural) - automatically pluralize a string - [pauseFor()](#pausefor) - pause the execution of a function for a given amount of time - [debounce()](#debounce) - call a function only once, after a given amount of time - [fetchAdvanced()](#fetchadvanced) - wrapper around the fetch API with a timeout option - [Arrays:](#arrays) - [randomItem()](#randomitem) - returns a random item from an array - [randomItemIndex()](#randomitemindex) - returns a tuple of a random item and its index from an array - [takeRandomItem()](#takerandomitem) - returns a random item from an array and mutates it to remove the item - [randomizeArray()](#randomizearray) - returns a copy of the array with its items in a random order

## Installation: - If you are using a bundler like webpack, you can install this package using npm: ``` npm i @sv443-network/userutils ``` Then, import it in your script as usual: ```ts import { addGlobalStyle } from "@sv443-network/userutils"; // or import * as userUtils from "@sv443-network/userutils"; ``` Shameless plug: I also have a [webpack-based template for userscripts in TypeScript](https://github.com/Sv443/Userscript.ts) that you can use to get started quickly.
- If you are not using a bundler, you can include the latest release from GreasyFork by adding this directive to the userscript header: ``` // @require https://greasyfork.org/scripts/TODO ```

## Preamble: This library is written in TypeScript and contains builtin TypeScript declarations. The usages and examples in this readme are written in TypeScript, but the library can also be used in plain JavaScript. Some functions require the `@run-at` or `@grant` directives to be tweaked in the userscript header or have other requirements. Their documentation will contain a section marked by a warning emoji (⚠️) that will go into more detail. If the usage contains multiple definitions of the function, each line represents an overload and you can choose which one you want to use.

## License: This library is licensed under the MIT License. See the [license file](./LICENSE.txt) for details.

## Features:
## DOM: ### onSelector() Usage: ```ts onSelector(selector: string, options: { listener: (elements: TElement | NodeListOf) => void, all?: boolean, continuous?: boolean, }): void ``` Registers a listener to be called whenever the element(s) behind a selector is/are found in the DOM. If the selector already exists, the listener will be called immediately. If `all` is set to `true`, querySelectorAll() will be used instead and the listener will return a NodeList of matching elements. This will also include elements that were already found in a previous listener call. If set to `false` (default), querySelector() will be used and only the first matching element will be returned. If `continuous` is set to `true`, the listener will not be deregistered after it was called once (defaults to false). When using TypeScript, the generic `TElement` can be used to specify the type of the element(s) that the listener will return. ⚠️ In order to use this function, [`initOnSelector()`](#initonselector) has to be called as soon as possible. This initialization function has to be called after `DOMContentLoaded` is fired (or immediately if `@run-at document-end` is set). Calling onSelector() before `DOMContentLoaded` is fired will not throw an error, but it also won't trigger listeners until the DOM is accessible.
Example - click to view ```ts document.addEventListener("DOMContentLoaded", initOnSelector); // Continuously checks if `div` elements are added to the DOM, then returns all of them (even previously detected ones) in a NodeList onSelector("div", { listener: (elements) => { console.log("Elements found:", elements); // type = NodeListOf }, all: true, continuous: true, }); // Checks if an input element with a value attribute of "5" is added to the DOM, then returns it and deregisters the listener onSelector("input[value=\"5\"]", { listener: (element) => { console.log("Element found:", element); // type = HTMLInputElement }, }); ```
### initOnSelector() Usage: ```ts initOnSelector(options?: MutationObserverInit): void ``` Initializes the MutationObserver that is used by [`onSelector()`](#onselector) to check for the registered selectors whenever a DOM change occurs on the `` By default, this only checks if elements are added or removed (at any depth). ⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired). The options object is passed directly to the MutationObserver.observe() method. Note that `options.subtree` and `options.childList` will be set to true by default. You may see all options [here](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#options), but these are the important ones: > Set `options.attributes` to `true` to also check for attribute changes on every single descendant of the `` (defaults to false). > Set `options.characterData` to `true` to also check for character data changes on every single descendant of the `` (defaults to false). > > ⚠️ Using these extra options can have a performance impact on larger sites or sites with a constantly changing DOM.
Example - click to view ```ts document.addEventListener("DOMContentLoaded", () => { initOnSelector({ attributes: true, characterData: true, }); }); ```

### getSelectorMap() Usage: `getSelectorMap(): Map` Returns a Map of all currently registered selectors and their options, including listener function. Since multiple listeners can be registered for the same selector, the value of the Map is an array of `OnSelectorOptions` objects.
Example - click to view ```ts document.addEventListener("DOMContentLoaded", initOnSelector); onSelector("div", { listener: (elements) => void 0, all: true, continuous: true, }); onSelector("div", { listener: (elements) => void 0, }); const selectorMap = getSelectorMap(); // Map(1) { // "div" => [ // { // listener: (elements) => void 0, // all: true, // continuous: true, // }, // { // listener: (elements) => void 0, // }, // ] // } ```
### getUnsafeWindow() Usage: `getUnsafeWindow(): Window` Returns the unsafeWindow object or falls back to the regular window object if the `@grant unsafeWindow` is not given. Userscripts are sandboxed and do not have access to the regular window object, so this function is useful for websites that reject some events that were dispatched by the userscript.
Example - click to view ```ts // trick the site into thinking the mouse was moved: const mouseEvent = new MouseEvent("mousemove", { view: getUnsafeWindow(), screenY: 69, screenX: 420, movementX: 10, movementY: 0, }); document.body.dispatchEvent(mouseEvent); ```

### insertAfter() Usage: `insertAfter(beforeElement: HTMLElement, afterElement: HTMLElement): HTMLElement` Inserts the element passed as `afterElement` as a sibling after the passed `beforeElement`. The passed `afterElement` will be returned. ⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
Example - click to view ```ts // insert a
as a sibling next to an element const beforeElement = document.querySelector("#before"); const afterElement = document.createElement("div"); afterElement.innerText = "After"; insertAfter(beforeElement, afterElement); ```

### addParent() Usage: `addParent(element: HTMLElement, newParent: HTMLElement): HTMLElement` Adds a parent element around the passed `element` and returns the new parent. Previously registered event listeners are kept intact. ⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
Example - click to view ```ts // add an around an element const element = document.querySelector("#element"); const newParent = document.createElement("a"); newParent.href = "https://example.org/"; addParent(element, newParent); ```

### addGlobalStyle() Usage: `addGlobalStyle(css: string): void` Adds a global style to the page in form of a `