Reputation: 1375
I'm trying to find out how far through a document a specific element is, ideally as a percentage.
Specifically, I have a long XHTML document (it's a component of an ePub file, in fact), and I've got one <span id="where_am_i">hello</span>
somewhere within it.
If this was the very first element in the document, the "percentage through" value would be 0. If it was exactly half-way through the document, it would be 50.
It won't necessarily be the top layer, it may be nested within other nodes.
I've considered using something like a recursive $(node).contents().each(function(){...});
and counting words to get to it, though I wonder if that might be a slow way to do it?
The document is text, it's very unlikely to contain images, or massively differing text size, so it's fine to just find out how far through the text #where_am_i
is.
Thank you in advance!
Upvotes: 0
Views: 89
Reputation: 707318
You can use this treeWalk function to find out where in the document a given element is:
Working demo: http://jsfiddle.net/jfriend00/LGT6x/
function findElementPercentage(target) {
var cnt = 0;
var pos;
treeWalkFast(document.body, function(node) {
if (node === target) {
pos = cnt;
}
++cnt;
});
// handle situation where target was not found
if (pos === undefined) {
return undefined;
}
// return percentage
return (pos / cnt) * 100;
}
var treeWalkFast = (function() {
// create closure for constants
var skipTags = {"SCRIPT": true, "IFRAME": true, "OBJECT": true,
"EMBED": true, "STYLE": true, "LINK": true, "META": true};
return function(parent, fn, allNodes) {
var node = parent.firstChild, nextNode;
while (node && node != parent) {
if (allNodes || node.nodeType === 1) {
if (fn(node) === false) {
return(false);
}
}
// if it's an element &&
// has children &&
// has a tagname && is not in the skipTags list
// then, we can enumerate children
if (node.nodeType === 1 && node.firstChild && !(node.tagName && skipTags[node.tagName])) {
node = node.firstChild;
} else if (node.nextSibling) {
node = node.nextSibling;
} else {
// no child and no nextsibling
// find parent that has a nextSibling
while ((node = node.parentNode) != parent) {
if (node.nextSibling) {
node = node.nextSibling;
break;
}
}
}
}
}
})();
FYI, you could probably also just use document.body.getElementsByTagName("*")
and then walk through the nodeList until you find your element and use that index as a measure of how far you are through the whole list.
function findElementPercentage(target) {
var all = document.body.getElementsByTagName("*");
for (var i = 0; i < all.length; i++) {
if (all[i] === target) {
return (i/all.length) * 100;
}
}
}
Working demo: http://jsfiddle.net/jfriend00/AUjq7/
Upvotes: 1
Reputation: 16068
Jquery solution:
<div>
<div id="test"></div>
<div></div>
</div>
<div id="result"></div>
var all=$("*").not("script, IFRAME, STYLE, EMBED, OBJECT, head, html,body, meta, title, link");
function getPercentage(el){
return all.index($(el))/all.length*100;
}
console.log(getPercentage("#test"))//25
Upvotes: 1
Reputation: 3120
If you have your document as a string, you can get a very rough estimate by using the indexOf javascript function
var html = $('body').html(); // or provided string
var percentage = html.indexOf('where_am_i') / html.length;
var found = percentage >= 0;
Upvotes: 1