Reputation: 6564
Running into a spot of trouble and basically trying to create a variable which can be used as a selector. eg
$('a').click(function(){
var selector = $(this).dompath();
});
HTML:
html
body
div
div /div
/div
ul
li
li
/ul
div
ul
li
li
li hello world
/ul
/div
body
html
this would then return something like
path = html body div ul li:contains('hello world')
then i could use this in a selector to select this div so if i did like
$(path).text() would return "hello world"
many thanks!
Upvotes: 8
Views: 15538
Reputation: 9094
Modified version of @jcern`s fantastic code.
Features:
#elementId
element.className
element
with it's innerHtml
appended (if any)<body>
and <html>
elements to shorten outputfunction dompath(element) {
var path = '',
i, innerText, tag, selector, classes;
for (i = 0; element && element.nodeType == 1; element = element.parentNode, i++) {
innerText = element.childNodes.length === 0 ? element.innerHTML : '';
tag = element.tagName.toLowerCase();
classes = element.className;
// Skip <html> and <body> tags
if (tag === "html" || tag === "body")
continue;
if (element.id !== '') {
// If element has an ID, use only the ID of the element
selector = '#' + element.id;
// To use this with jQuery, return a path once we have an ID
// as it's no need to look for more parents afterwards.
//return selector + ' ' + path;
} else if (classes.length > 0) {
// If element has classes, use the element tag with the class names appended
selector = tag + '.' + classes.replace(/ /g , ".");
} else {
// If element has neither, print tag with containing text appended (if any)
selector = tag + ((innerText.length > 0) ? ":contains('" + innerText + "')" : "");
}
path = ' ' + selector + path;
}
return path;
}
Upvotes: 6
Reputation: 21086
The request is kind of silly, since there's a much better way.
Either assign a unique ID to the element to quickly reference it later, or if an ID is already assigned use it.
//
// generate a unique (enough) id for an element if necessary
//
function getUID(id) {
if(window["uidCounter"]==null)
window["uidCounter"]=0;
return id||( (window["uidCounter"]++) + "_" + (new Date()).getTime() );
}
//
// use an #ID selector
//
$('a').click(function(){
var uid = getUID( $(this).attr('id') );
$(this).attr('id', uid);
var selector = "#" + uid;
});
Upvotes: 0
Reputation: 16917
You would need enumerate all parents of the element you want to create a query for, and add a selector for each parent, e.g. the node name of the parent or the name with the contains-test, if that test is needed for that parent. The only way to be sure, if this contains-test is needed, is probably to apply the current query against the current parent in each step and check, if the query only returns the target element. Then add the contains-test if it matches too much...
I wrote a Greasemonkey script doing that. First it collects all elements that are needed to find the target element in another tree ("template") and then converts that to a query. However, it uses the attributes (specifically class/id/name ) instead of the text for matching, and the position, if the attributes are not unique enough, since I think in most cases the text changes more often than the structure.
Upvotes: 0
Reputation: 7848
Perhaps something like this:
function dompath( element )
{
var path = '';
for ( ; element && element.nodeType == 1; element = element.parentNode )
{
var inner = $(element).children().length == 0 ? $(element).text() : '';
var eleSelector = element.tagName.toLowerCase() +
((inner.length > 0) ? ':contains(\'' + inner + '\')' : '');
path = ' ' + eleSelector + path;
}
return path;
}
This modified a method from another question to go through, and add in the full text contents of the tag via a :contains()
operator only if the tag has no children tags.
I had tested with this method:
$(document).ready(function(){
$('#p').click(function() {
console.log(dompath(this));
});
});
Against this:
<html>
<body>
<div>
<div> </div>
</div>
<ul>
<li></li>
<li></li>
</ul>
<div>
<ul>
<li id="p">hi</li>
<li></li>
<li id="p2">hello world</li>
</ul>
</div>
<body>
<html>
The results of clicking on p then get output as:
html body div ul li:contains('hi')
Upvotes: 16