-
Notifications
You must be signed in to change notification settings - Fork 779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(options): add ancestry CSS selector to nodes #2389
Changes from 7 commits
c711cd3
5c879a1
17f317d
79e334c
15a8ca9
e10eada
03178e6
c538337
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import getShadowSelector from './get-shadow-selector'; | ||
|
||
function generateAncestry(node) { | ||
const nodeName = node.nodeName.toLowerCase(); | ||
const parent = node.parentElement; | ||
if (!parent) { | ||
return nodeName; | ||
} | ||
|
||
let nthChild = ''; | ||
if ( | ||
nodeName !== 'head' && | ||
nodeName !== 'body' && | ||
parent.children.length > 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better if this was only checking if the parent had multiple of the nodeName? I know Right now if the parent has two children but they are both different nodeNames, you still get the nth-child selector which doesn't do much but add noise:
Results in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would the benefit of that be? This seems faster. |
||
) { | ||
const index = Array.prototype.indexOf.call(parent.children, node) + 1; | ||
nthChild = `:nth-child(${index})`; | ||
} | ||
|
||
return generateAncestry(parent) + ' > ' + nodeName + nthChild; | ||
} | ||
|
||
/** | ||
* Gets a unique CSS selector | ||
* @param {HTMLElement} node The element to get the selector for | ||
* @param {Object} optional options | ||
* @returns {String|Array<String>} Unique CSS selector for the node | ||
*/ | ||
export default function getAncestry(elm, options) { | ||
return getShadowSelector(generateAncestry, elm, options); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/** | ||
* Gets a unique CSS selector | ||
* @param {HTMLElement} node The element to get the selector for | ||
* @param {Object} optional options | ||
* @returns {String|Array<String>} Unique CSS selector for the node | ||
*/ | ||
function getShadowSelector(generateSelector, elm, options = {}) { | ||
if (!elm) { | ||
return ''; | ||
} | ||
let doc = (elm.getRootNode && elm.getRootNode()) || document; | ||
// Not a DOCUMENT_FRAGMENT - shadow DOM | ||
if (doc.nodeType !== 11) { | ||
return generateSelector(elm, options, doc); | ||
} | ||
|
||
let stack = []; | ||
while (doc.nodeType === 11) { | ||
if (!doc.host) { | ||
return ''; | ||
} | ||
stack.unshift({ elm, doc }); | ||
elm = doc.host; | ||
doc = elm.getRootNode(); | ||
} | ||
|
||
stack.unshift({ elm, doc }); | ||
return stack.map(({ elm, doc }) => generateSelector(elm, options, doc)); | ||
} | ||
|
||
export default getShadowSelector; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should cache these results on the virtual node as we process them so we aren't recalculating the entire ancestry tree of every descendant of a node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why that would make much of a difference. The way this is written is very fast. I doubt doing a lookup in a large set is going to be noticeably faster than walking a an additional two or three ancestors.