I've managed to do it, but, although the trie works in my version, it's kinda useless because it seems getComputedStyle
always returns the color's rgb representation (which is why I had to include it in the trie).
I tried to make it as generic as possible so that you can use this with other dfs problems
class Trie {
value = ''
children = []
constructor(...keys) {
const firstLetters = Array.from(new Set(keys.map(k => k[0])))
this.children = firstLetters.map(l => {
return {
...new Trie(...keys.filter(k => k.startsWith(l)).map(k => k.substring(1))),
value: l,
}
})
}
}
const whiteColorTrie = new Trie('white', '#fff', '#ffffff', 'rgb(255, 255, 255)')
const existsInTrie = (trie, search, initialValue = '') => {
const { value } = trie
const acc = initialValue + (value ?? '')
if (!search.startsWith(acc)) return false
if (search === acc && acc.length !== 0) return true
return trie.children.some(node => existsInTrie(node, search, acc))
}
const dfs = (root, getChildNodes, predicate) => {
const children = getChildNodes(root)
const matches = []
if (predicate(root)) matches.push(root)
children.forEach(child =>
matches.push(...dfs(child, getChildNodes, predicate))
)
return matches
}
const elements = dfs(
document.body,
node => [...node.children],
node => existsInTrie(whiteColorTrie, getComputedStyle(node).color)
)
Since the trie isn't really doing anything, here's a version of the code that doesn't include it, making it a lot simpler:
const dfs = (root, getChildNodes, predicate) => {
const children = getChildNodes(root)
const matches = []
if (predicate(root)) matches.push(root)
children.forEach(child =>
matches.push(...dfs(child, getChildNodes, predicate))
)
return matches
}
const elements = dfs(
document.body,
node => [...node.children],
node => getComputedStyle(node).color === 'rgb(255, 255, 255)'
)