Created
December 14, 2022 00:02
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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