Reputation: 1145
I'm trying to write a pure javascript function that will take an element from the page (generally a <div>) and from there work out which if it has any specific child elements. Which will essentially be any tag that signifies textual content, so: <p>
or any header tag so (<h1>
.. <h6>
) or lists etc.
I'm not looking to manipulate these elements simply check for their existence.
So the function would take the form
/**
* Takes an element and returns whether
* the element contains content
* @return boolean (true/false)
*/
var isContent = function (elementToCheck) {
};
I'm currently using document.getElementsByTagName('div')
to get all the <div>
elements of the page. I will then parse these into the function one at a time.
I've currently got this down
var isContent = function (elementToCheck) {
if (elementToCheck.hasChildNodes()) {
var children = elementToCheck.childNodes;
for (var i = 0; i < children.length; i++) {
// handle children[i]
}
}
}
I've been trying out using chilren[i].nodeValue
and testing for equality with various things but I can't get any of them to pass.
What would be the best way to carry on with this? I think it's turning in to a messy function as I'm having to get all the elements outside of this, loop over them and parse them in here which then performs another loop. I'm starting to wonder if it's possible to do it with a regex?
Upvotes: 2
Views: 1636
Reputation: 2423
This way you do not need jQuery, do not need to (but can) specify the tags you want the textual content of and can apply a regex to the found texts.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
function logTextContent(elem) {
var childNodes = elem.childNodes;
for(var i=0; i<childNodes.length; i++) {
var nodex = childNodes[i];
if(nodex.nodeType == 3 /* text node */) {
var textContent = nodex.nodeValue;
if(textContent.match(/\S+/) /* apply regex */) {
console.log("found text: "+textContent);
}
}
else if (nodex.nodeType == 1 /* element node*/) {
logTextContent(nodex)
}
}
}
function findDocumentTexts() {
var docElems = document.getElementsByTagName("body");
for(var i=0; i<docElems.length; i++) {
var elem = docElems[i];
logTextContent(elem);
}
}
</script>
</head>
<body>
<button onclick="findDocumentTexts()">find document texts</button>
<!-- I will fail -->
<div>
<!-- I will pass -->
<div>
<h1>Heading</h1>
<p>
I should be found straight away
</p>
</div>
<!-- I will fail -->
<div>
<!-- I will pass -->
<div>
<p>
I will be missed by the first div but found by the second
</p>
</div>
</div>
</div>
</body>
</html>
Upvotes: 0
Reputation: 4020
I've had a bash at this, though Pointy has mentioned a function new to me called querySelectorAll()
that might let you cut out the containsTextElements
loop.
var textTags = ["h1", "h2", "h3", "h4", "h5", "h6", "p"];
var containsTextElements = function(elementToCheck) {
for (var i = 0; i < textTags.length; i++) {
if(elementToCheck.getElementsByTagName(textTags[i]).length > 0)
return true;
}
return false;
}
var doStuffToDivsWithText = function(callback) {
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++ ) {
if(containsTextElements(divs[i]))
callback(divs[i]);
};
}
doStuffToDivsWithText(function(div) {
console.log(div.id);
});
Upvotes: 0
Reputation: 413720
If what you want is to find all <div>
elements that have at least one child node that's got a non-empty content model, then something like this work in all browsers back to (and including) IE8:
function findDivWithContents() {
var allDivs = document.getElementsByTagName('div');
var di, divs = [];
for (di = 0; di < allDivs.length; ++di) {
if (allDivs[di].querySelectorAll('p, span, h1, h2, h3, h4, ... ').length > 0)
divs.push(allDivs[di]);
return divs;
}
That uses .querySelectorAll()
to find your container elements. (You'd have to complete the list of course.)
edit alternatively, you could do it backwards: iterate through all the container type elements you're interested in, and check to see if their parent is a <div>
:
function findTheDivs() {
var containers = document.querySelectorAll('p, span, div, h1, h2, h3, ... ');
var i, divs = [];
for (i = 0; i < containers.length; ++i) {
if (containers[i].parentNode.tagName === 'DIV')
divs.push(containers[i].parentNode);
return divs;
}
I think this is probably way more efficient. (It might be necessary to add a nonsense "class" marker to each <div>
to avoid adding it to the list more than once.)
Upvotes: 1