Created
April 1, 2024 22:11
-
-
Save cmrfrd/5d3ccda3dc26b65cfd46a93d2fc0f77a to your computer and use it in GitHub Desktop.
visibile_elements.ts
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
const clickableElements = await page.evaluate(async () => { | |
const resultElements: Elem[] = [] | |
const clickables = [ | |
'a', | |
'button', | |
'input', | |
'textarea', | |
'select', | |
'details', | |
'summary' | |
] | |
function isVisible(elem: Element) { | |
const rect = elem.getBoundingClientRect() | |
const inViewport = | |
rect.top >= 0 && | |
rect.left >= 0 && | |
rect.bottom <= window.innerHeight && | |
rect.right <= window.innerWidth | |
if (!inViewport) return false | |
const style = getComputedStyle(elem) | |
if (style.display === 'none') return false | |
if (style.visibility !== 'visible') return false | |
const elemCenter = { | |
x: rect.left + rect.width / 2, | |
y: rect.top + rect.height / 2 | |
} | |
if (elemCenter.x < 0) return false | |
if ( | |
elemCenter.x > | |
(document.documentElement.clientWidth || window.innerWidth) | |
) | |
return false | |
if (elemCenter.y < 0) return false | |
if ( | |
elemCenter.y > | |
(document.documentElement.clientHeight || | |
window.innerHeight) | |
) | |
return false | |
let pointContainer = document.elementFromPoint( | |
elemCenter.x, | |
elemCenter.y | |
) | |
if (!pointContainer) return false | |
let candidatePointContainer: Element | null | |
while (pointContainer) { | |
if (pointContainer === elem) return true | |
candidatePointContainer = | |
pointContainer.parentNode as Element | |
if (!candidatePointContainer) break | |
pointContainer = candidatePointContainer | |
} | |
return false | |
} | |
const aspectRatio = (w: number, h: number) => { | |
if ( | |
typeof w != 'number' || | |
typeof h != 'number' || | |
isNaN(w) || | |
isNaN(h) | |
) | |
throw new Error('Invalid input') | |
if (!w || !h) return 0 | |
return Math.max(w, h) / Math.min(w, h) | |
} | |
document.querySelectorAll('body *').forEach((el) => { | |
if (!el) return | |
const rect = el.getBoundingClientRect() | |
if (!isVisible(el)) return | |
const area = rect.width * rect.height | |
const ar = aspectRatio(rect.width, rect.height) | |
if (area < 512 || ar > 16) return | |
const isClickable = | |
clickables.includes(el.tagName.toLowerCase()) || | |
el.getAttribute('href') != null || | |
el.getAttribute('onclick') != null || | |
window.getComputedStyle(el).cursor == 'pointer' | |
if (!isClickable) return | |
resultElements.push({ | |
element: el, | |
tag: el.tagName, | |
area, | |
aspectRatio: ar, | |
rect, | |
html: el.outerHTML | |
}) | |
}) | |
return resultElements.filter( | |
(x) => | |
!resultElements.some( | |
(y) => y.html.includes(x.html) && !(x.html == y.html) | |
) | |
) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment