Skip to content

Instantly share code, notes, and snippets.

@williamyeny
Created December 14, 2022 00:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save williamyeny/a18e7184afa3974688af6ce64e50f61b to your computer and use it in GitHub Desktop.
Save williamyeny/a18e7184afa3974688af6ce64e50f61b to your computer and use it in GitHub Desktop.
Writen for a Chrome extension. It checks for a specific element on the page and calls a callback when it's found.
// Writen for a Chrome extension. It checks for a specific element on the page and calls a callback when it's found.
// Returns an element and all its child elements.
const getAllElements = (node: Node): Element[] => {
if (!(node instanceof Element)) {
return [];
}
const nodes = [node];
if (node.childNodes) {
nodes.push(...[...node.childNodes].flatMap(getAllElements));
}
return nodes;
};
// Waits for a specified element.
export const getObserver = (cb: (element: Element) => void) => {
let hasElement = false;
const isNodeMatch = (node: Node): boolean => {
// Modify the second condition to match your element.
return node instanceof Element && node.id === "my-id";
};
const observer = new MutationObserver((records) => {
for (const record of records) {
if (record.type === "childList") {
if (!hasElement) {
// Check if any of the added nodes is a match.
for (const element of [...record.addedNodes].flatMap(
getAllElements
)) {
if (isNodeMatch(element)) {
hasElement = true;
cb(element);
return;
}
}
} else {
// Check if any of the removed nodes is a match.
for (const element of [...record.removedNodes].flatMap(
getAllElements
)) {
if (isNodeMatch(element)) {
hasElement = false;
return;
}
}
}
} else if (
// If attributes change, check if the target node is a match.
record.type === "attributes" &&
!hasElement &&
isNodeMatch(record.target)
) {
hasElement = true;
cb(record.target as Element);
return;
}
}
});
observer.observe(document.body, {
subtree: true,
childList: true,
// If the element you want to find changes attributes, you can use these.
// attributes: true,
// attributeFilter: ["id"],
});
return observer;
};
// Usage:
const observer = getObserver((element) => {
// Do something with the element once found, like mounting a React app.
console.log(element);
});
// If you want to stop observing, call `observer.disconnect()`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment