Reputation: 104
Suppose my DOM looks something like this (purely fictional example):
<div>
<img id="img1" />
Text 1
</div>
<img id="img2" />
<div>
<p>Text 2</p>
<div>
<img id="img3" />
</div>
<img id="img4" />
</div>
What I'm attempting to do is to find all text (if any) between consecutive elements independent of nesting level (so in this case, I'd find Text1
between #img1
and #img2
, Text 2
between #img2
and #img3
, and nothing/an empty string between #img3
and #img4
)
I don't know ahead of time how the dom is going to be structured.
I've tried using JQuery's nextUntil(), but that only seems to work for sibling nodes.
Upvotes: 2
Views: 147
Reputation: 195992
You can use the contents()
method which returns all child nodes including textnodes.
This way, doing $('body *').contents().addBack()
returns a flattened representation of the DOM.
Now, you can iterate between img
(or whatever tag you want) elements and get the textnodes (having a nodeType
of 3)
function textBetweenTags(tag){
var contents = $('body *').contents().addBack(),
allOfType = contents.filter(tag),
count = allOfType.length,
map = allOfType.map(function(){return contents.index( this );}),
texts = [];
for (var i = 0, l = map.length-1; i < l; i++){
var start = map[i],
end = map[i+1],
textnodes = contents.slice(start,end).get().filter(function(item,index){return item.nodeType===3;});
texts.push( {
start: contents[start],
end: contents[end],
text: $.trim($(textnodes).text())
});
}
return texts.filter(function(item,index){return item.text !== '';});
}
var texts = textBetweenTags('img');
console.log(texts);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img id="img1" />
Text 1
</div>
<img id="img2" />
<div>
<p>Text 2</p>
<div>
<img id="img3" />
</div>
<img id="img4" />
</div>
Upvotes: 1
Reputation: 4783
I think my solution is more closely achieves what you specified. This is also using contents()
but does the traversing/filtering too, based on the ids.
function textBetweenIds(firstId, lastId) {
var texts = [],
betweenIds = false,
recurse = function ($item) {
$item.each(function() {
var text,
$item = $(this),
itemId = $item.attr("id"),
contents = $item.contents();
if (itemId == firstId) {
betweenIds = true;
} else if (itemId == lastId) {
betweenIds = false;
}
if (contents.length == 0 && betweenIds) {
text = $item.text().trim();
if (text != undefined && text.length > 0) {
texts.push(text);
}
}
recurse(contents);
});
return texts;
};
recurse($("body"));
return texts;
}
result = textBetweenIds("img1", "img3");
// result: ["Text 1", "Text 2"]
Upvotes: 0