I'm using nextUntil
method to get all stuff between two elements. But this method does not include text nodes
to output. It gives an array like [<br>, <br>, <br>]
. How can I get all stuff including text nodes?
This is the HTML code:
$('.content a:contains("spoiler").b:even').each(function() {
$(this).nextUntil('.content a:contains("spoiler").b')
.wrapAll('<div style="border:solid 1px black;"></div>');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
--- <a class="b" href="/?q=spoiler">spoiler</a> ---
<br>
<br> dangerous text here
<br> --- <a class="b" href="/?q=spoiler">spoiler</a> ---
<br> safe text here
<br> --- <a class="b" href="/?q=spoiler">spoiler</a> ---
<br>
<br> dangerous text here
<br> --- <a class="b" href="/?q=spoiler">spoiler</a> ---
</div>
JSFiddle: http://jsfiddle.net/Lwk97rvq/1/
Only the jQuery .contents()
method returns all nodes (including text nodes, normally ignored).
So maybe something like this?:
http://jsfiddle.net/ykv3gf5L/2/
$('.content').each(function () {
var open = false;
var result = $();
$(this).contents().each(function () {
var $this = $(this);
if ($this.text() == "spoiler") {
if (open) {
result.wrapAll('<div style="border:solid 1px black;"></div>');
open = false;
} else {
result = $();
open = true;
}
} else {
result = result.add($this)
}
});
if (open) {
result.wrapAll('<div style="border:solid 1px black;"></div>');
}
});
It just iterate all nodes and based on a flag starts a new collection, or wraps the nodes found.
The final if (open)
allows for an unclosed spolier block within a content
classed div.
Notes:
$()
is an empty jQuery collection (like an empty array but for jQuery objects)
- I suggest you use a style for your spoilers and use a class e.g.
result.wrapAll('<div class="spoiler"></div>');
e.g. http://jsfiddle.net/ykv3gf5L/3/
You can create your own jquery plugin which does the same as nextUntil
but includes text nodes:
$.fn.nextUntilWithTextNodes = function (until) {
var matched = $.map(this, function (elem, i, until) {
var matched = [];
while ((elem = elem.nextSibling) && elem.nodeType !== 9) {
if (elem.nodeType === 1 || elem.nodeType === 3) {
if (until && jQuery(elem).is(until)) {
break;
}
matched.push(elem);
}
}
return matched;
}, until);
return this.pushStack(matched);
};
So you can call this nextUntilWithTextNodes
instead of nextUntil
and you are good to go.