Created
November 2, 2023 11:38
-
-
Save lifeart/6a6ceb08ee131b6c14918e04d824bf06 to your computer and use it in GitHub Desktop.
resolve item selector on page with list of items
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
var classes = {}; | |
var cnt = 1; | |
function hashForClass(rawClassName) { | |
const className = rawClassName.trim(); | |
if (className in classes) { | |
classes[className].cnt++; | |
return classes[className].index; | |
} else { | |
classes[className] = { | |
index: cnt, | |
cnt: 1, | |
}; | |
cnt++; | |
return classes[className].index; | |
} | |
} | |
function generateSelectors(node, selector = '') { | |
// Base case: if the node is not an element or doesn't have a parent, return an empty array | |
if (!node || node.nodeType !== 1 || !node.parentElement) return []; | |
if ( | |
node.tagName === 'SVG' || | |
node.tagName === 'SCRIPT' || | |
node.tagName === 'NOSCRIPT' || | |
node.tagName === 'STYLE' | |
) | |
return []; | |
if (typeof node.className !== 'string') { | |
return []; | |
} | |
// Generate a selector for the current node | |
const nodeName = node.nodeName.toLowerCase(); | |
const idSelector = node.id ? `#${node.id}` : ''; | |
const classSelectors = node.className | |
.split(' ') | |
.sort() | |
.map((cls) => (cls ? `.${hashForClass(cls)}` : '')) | |
.join(''); | |
const currentSelector = `${nodeName}${idSelector}${classSelectors}`; | |
// Build the complete selector for the current node | |
const completeSelector = selector ? selector + ' > ' + currentSelector : currentSelector; | |
// Generate selectors for the child nodes | |
const childSelectors = Array.from(node.children).flatMap((child) => | |
generateSelectors(child, completeSelector), | |
); | |
// Return the selector for the current node, along with the selectors for the child nodes | |
return [completeSelector].concat(childSelectors); | |
} | |
// Usage: | |
const selectors = generateSelectors(document.body); | |
function frequencyMapForSelectors(selectors) { | |
const frequencyMap = {}; | |
for (const selector of selectors) { | |
if (selector in frequencyMap) { | |
frequencyMap[selector].count += 1; | |
} else { | |
const nestedChildren = selectors.filter((k) => k.startsWith(selector) && k !== selector); | |
frequencyMap[selector] = { | |
count: 1, | |
depth: selector.split('>').length, | |
children: nestedChildren.length, | |
}; | |
} | |
} | |
let selectorWithMaxChildren = ''; | |
let maxChildren = 0; | |
Object.keys(frequencyMap).forEach((key) => { | |
const ref = frequencyMap[key]; | |
if (ref.children < 1) { | |
delete frequencyMap[key]; | |
} | |
if (ref.count <= 2) { | |
delete frequencyMap[key]; | |
} | |
}); | |
Object.keys(frequencyMap).forEach((key) => { | |
const ref = frequencyMap[key]; | |
if (ref.children > maxChildren) { | |
maxChildren = ref.children; | |
selectorWithMaxChildren = key; | |
} | |
}); | |
const selector = selectorWithMaxChildren | |
.split('>') | |
.pop() | |
.split('.') | |
.map((cls) => { | |
const c = parseInt(cls); | |
return Object.keys(classes).find((key) => classes[key].index === parseInt(c)); | |
}) | |
.filter((cls) => cls !== undefined) | |
.join('.'); | |
return '.' + selector; | |
} | |
console.log(frequencyMapForSelectors(selectors)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment