Last active
October 8, 2019 17:56
-
-
Save tomhodgins/fd699734d6f6cc901b0fd6d46d15ec80 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Point & Click Selector Builder | |
// Simple CSS Selector | |
function simpleSelector(node) { | |
const buildTag = tag => { | |
let tagName = tag.tagName.toLowerCase() | |
let className = Array.from(tag.classList).filter(name => name.includes('=') === false).join('.') | |
let attributes = ( | |
tag.id.length | |
? `#${tag.id}` | |
: '' | |
) + ( | |
className.length | |
? `.${className}` | |
: '' | |
) | |
return tagName + (attributes.length ? attributes : '') | |
} | |
let current = node | |
let selector = buildTag(current) | |
while ( | |
current.parentElement | |
&& current.parentElement !== document.documentElement | |
) { | |
selector = `${buildTag(current.parentElement)} ${selector}` | |
current = current.parentElement | |
} | |
return selector | |
} | |
// Specific CSS Selector | |
function superSpecificSelector(node) { | |
const buildTag = tag => { | |
const tagName = tag.tagName.toLowerCase() | |
const attributes = Array.from(tag.attributes) | |
.reduce( | |
(acc, attr) => { | |
switch (attr.name) { | |
case 'id': | |
return acc += `#${attr.value}` | |
case 'class': | |
let string = attr.value | |
.split(' ') | |
.filter(name => { | |
return name.includes('=') === false | |
}) | |
.join('.') | |
return acc += string.length ? | |
`.${string}` | |
: '' | |
default: | |
return acc += `[${attr.name}="${attr.value.replace(/"/g, '\\"')}"]` | |
} | |
}, | |
'' | |
) | |
let siblings = Array.from(tag.parentNode.children) | |
let index = '' | |
if (tag !== document.body) { | |
if (siblings.indexOf(tag) === 0) { | |
index = ':first-child' | |
} else if (siblings.indexOf(tag) === siblings.length) { | |
index = ':last-child' | |
} else { | |
index = `:nth-child(${siblings.indexOf(tag) + 1})` | |
} | |
} | |
return tagName + attributes + index | |
} | |
let current = node | |
let selector = buildTag(current) | |
while ( | |
current.parentElement | |
&& current.parentElement !== document.documentElement | |
) { | |
selector = `${buildTag(current.parentElement)} > ${selector}` | |
current = current.parentElement | |
} | |
return selector | |
} | |
// Tree-based Skeleton Selector | |
function skeletonSelector( | |
element = document.documentElement, | |
option = 'long' || 'short' | |
) { | |
let selector = [] | |
let current = element | |
while (current.parentElement) { | |
let index = [...current.parentElement.children].indexOf(current) | |
let formula = { | |
// *:nth-of-type(2) | |
short: num => `*:nth-child(${num + 1})`, | |
// * + * | |
long: num => '*'.repeat(num + 1).split('').join(' + ') | |
} | |
selector.push(formula[option](index)) | |
current = current.parentElement | |
} | |
return [...selector, ':root'].reverse().join(' > ') | |
} | |
// Try to generate the simplest selector that matches the element | |
function generateSelector(node) { | |
return [ | |
simpleSelector(node), | |
superSpecificSelector(node), | |
skeletonSelector(node, 'short'), | |
skeletonSelector(node, 'long') | |
].find(selector => | |
node === document.querySelector(selector) | |
) | |
} | |
// Log generated selector to console on click | |
window.addEventListener('click', event => { | |
event.preventDefault() | |
console.log(generateSelector(event.target)) | |
}) | |
// Add On-Page Hover style effect for showing boundaries of elements | |
const selectors = Array.from(document.querySelectorAll('*')).map(tag => generateSelector(tag)) | |
document.documentElement.appendChild( | |
document.createElement('style') | |
).textContent = ` | |
:hover { | |
box-shadow: inset red 0 0 0 1px !important; | |
} | |
${selectors.join(', ')}:hover { | |
position: relative !important; | |
cursor: pointer !important; | |
} | |
${selectors.map(selector => ` | |
${selector}:hover::before { | |
content: "${selector}"; | |
font-size: 10pt !important; | |
position: absolute !important; | |
top: 0 !important; | |
left: 0 !important; | |
padding: .25em !important; | |
font-family: monospace !important: | |
font-weight: 400 !important; | |
color: black !important; | |
background-color: white !important; | |
z-index: 9999 !important; | |
} | |
`).join('\n')} | |
` | |
;'Point and click to log selector to console'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment