|
@@ -5,9 +5,7 @@
|
|
|
|
|
|
import { PlatformError } from "./errors.js";
|
|
|
|
|
|
-/** Whether the DOM has finished loading */
|
|
|
-let domReady = false;
|
|
|
-document.addEventListener("DOMContentLoaded", () => domReady = true);
|
|
|
+//#region unsafeWindow
|
|
|
|
|
|
/**
|
|
|
* Returns `unsafeWindow` if the `@grant unsafeWindow` is given, otherwise falls back to the regular `window`
|
|
@@ -22,6 +20,8 @@ export function getUnsafeWindow(): Window {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//#region addParent
|
|
|
+
|
|
|
/**
|
|
|
* Adds a parent container around the provided element
|
|
|
* @returns Returns the new parent element
|
|
@@ -38,6 +38,8 @@ export function addParent<TElem extends Element, TParentElem extends Element>(el
|
|
|
return newParent;
|
|
|
}
|
|
|
|
|
|
+//#region addGlobalStyle
|
|
|
+
|
|
|
/**
|
|
|
* Adds global CSS style in the form of a `<style>` element in the document's `<head>`
|
|
|
* This needs to be run after the `DOMContentLoaded` event has fired on the document object (or instantly if `@run-at document-end` is used).
|
|
@@ -51,6 +53,8 @@ export function addGlobalStyle(style: string): HTMLStyleElement {
|
|
|
return styleElem;
|
|
|
}
|
|
|
|
|
|
+//#region preloadImages
|
|
|
+
|
|
|
/**
|
|
|
* Preloads an array of image URLs so they can be loaded instantly from the browser cache later on
|
|
|
* @param rejects If set to `true`, the returned PromiseSettledResults will contain rejections for any of the images that failed to load. Is set to `false` by default.
|
|
@@ -59,14 +63,16 @@ export function addGlobalStyle(style: string): HTMLStyleElement {
|
|
|
export function preloadImages(srcUrls: string[], rejects = false): Promise<PromiseSettledResult<HTMLImageElement>[]> {
|
|
|
const promises = srcUrls.map(src => new Promise<HTMLImageElement>((res, rej) => {
|
|
|
const image = new Image();
|
|
|
- image.addEventListener("load", () => res(image));
|
|
|
- image.addEventListener("error", (evt) => rejects && rej(evt));
|
|
|
+ image.addEventListener("load", () => res(image), { once: true });
|
|
|
+ image.addEventListener("error", (evt) => rejects && rej(evt), { once: true });
|
|
|
image.src = src;
|
|
|
}));
|
|
|
|
|
|
return Promise.allSettled(promises);
|
|
|
}
|
|
|
|
|
|
+//#region openInNewTab
|
|
|
+
|
|
|
/**
|
|
|
* Tries to use `GM.openInTab` to open the given URL in a new tab, otherwise if the grant is not given, creates an invisible anchor element and clicks it.
|
|
|
* For the fallback to work, this function needs to be run in response to a user interaction event, else the browser might reject it.
|
|
@@ -110,6 +116,8 @@ export function openInNewTab(href: string, background?: boolean, additionalProps
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//#region interceptEvent
|
|
|
+
|
|
|
/**
|
|
|
* Intercepts the specified event on the passed object and prevents it from being called if the called {@linkcode predicate} function returns a truthy value.
|
|
|
* If no predicate is specified, all events will be discarded.
|
|
@@ -150,6 +158,8 @@ export function interceptEvent<
|
|
|
})(eventObject.__proto__.addEventListener);
|
|
|
}
|
|
|
|
|
|
+//#region interceptWindowEvent
|
|
|
+
|
|
|
/**
|
|
|
* Intercepts the specified event on the window object and prevents it from being called if the called {@linkcode predicate} function returns a truthy value.
|
|
|
* If no predicate is specified, all events will be discarded.
|
|
@@ -163,6 +173,8 @@ export function interceptWindowEvent<TEvtKey extends keyof WindowEventMap>(
|
|
|
return interceptEvent(getUnsafeWindow(), eventName, predicate);
|
|
|
}
|
|
|
|
|
|
+//#region isScrollable
|
|
|
+
|
|
|
/** Checks if an element is scrollable in the horizontal and vertical directions */
|
|
|
export function isScrollable(element: Element): Record<"vertical" | "horizontal", boolean> {
|
|
|
const { overflowX, overflowY } = getComputedStyle(element);
|
|
@@ -172,6 +184,8 @@ export function isScrollable(element: Element): Record<"vertical" | "horizontal"
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+//#region observeElementProp
|
|
|
+
|
|
|
/**
|
|
|
* Executes the callback when the passed element's property changes.
|
|
|
* Contrary to an element's attributes, properties can usually not be observed with a MutationObserver.
|
|
@@ -215,6 +229,8 @@ export function observeElementProp<
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//#region getSiblingsFrame
|
|
|
+
|
|
|
/**
|
|
|
* Returns a "frame" of the closest siblings of the {@linkcode refElement}, based on the passed amount of siblings and {@linkcode refElementAlignment}
|
|
|
* @param refElement The reference element to return the relative closest siblings from
|
|
@@ -264,6 +280,8 @@ export function getSiblingsFrame<
|
|
|
return [] as TSibling[];
|
|
|
}
|
|
|
|
|
|
+//#region setInnerHtmlUnsafe
|
|
|
+
|
|
|
let ttPolicy: { createHTML: (html: string) => string } | undefined;
|
|
|
|
|
|
/**
|
|
@@ -287,6 +305,8 @@ export function setInnerHtmlUnsafe<TElement extends Element = HTMLElement>(eleme
|
|
|
return element;
|
|
|
}
|
|
|
|
|
|
+//#region probeElementStyle
|
|
|
+
|
|
|
/**
|
|
|
* Creates an invisible temporary element to probe its rendered style.
|
|
|
* Has to be run after the `DOMContentLoaded` event has fired on the document object.
|
|
@@ -326,11 +346,18 @@ export function probeElementStyle<
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+//#region isDomLoaded
|
|
|
+
|
|
|
+let domReady = false;
|
|
|
+document.addEventListener("DOMContentLoaded", () => domReady = true, { once: true });
|
|
|
+
|
|
|
/** Returns whether or not the DOM has finished loading */
|
|
|
export function isDomLoaded(): boolean {
|
|
|
return domReady;
|
|
|
}
|
|
|
|
|
|
+//#region onDomLoad
|
|
|
+
|
|
|
/**
|
|
|
* Executes a callback and/or resolves the returned Promise when the DOM has finished loading.
|
|
|
* Immediately executes/resolves if the DOM is already loaded.
|
|
@@ -347,6 +374,6 @@ export function onDomLoad(cb?: () => void): Promise<void> {
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
|
cb?.();
|
|
|
res();
|
|
|
- });
|
|
|
+ }, { once: true });
|
|
|
});
|
|
|
}
|