Reputation: 95
I've got a problem and I just don't know how to solve this (relatively) simple function. What i want to achieve is the following. My client is using a CMS wich gives me this output.
<div class="foldOutEnabled">
<h2>Title 01</h2>
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
<h3>subtitle 01</h3>
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
<h2>Title 02</h2>
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
<h3>subtitle 02</h3>
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
</div>
What i am trying to do is get all HTML between the 'h2' tags and wrap this in another div (so jQUery can make an accordion menu with it). For this to work i need the output to become this,
<div class="foldOutItem">
<div class="foldOutItemTitle">
<h2>
<a href="#"><img class="foldoutArrow" width="17" height="20" alt="" src="../images/footer-arrow.png">Title 01</a>
</h2>
</div>
<div class="foldOutItemContent">
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
<h3>subtitle 01</h3>
<p>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus tortor ligula, pulvinar eget vestibulum quis, lobortis et quam.</p>
</div>
</div>
etc...
After trying many different solutions and ways i've come as far is the following,
if ($('.foldOutEnabled').length) {
var newHtml = '<div class="foldOutTitle"><span><a id="foldOutAll" href="#">Alles uitklappen</a></span></div>';
$('.foldOutEnabled h2, .foldOutEnabled h3, .foldOutEnabled table, .foldOutEnabled p, .foldOutEnabled span').each(function(i) {
if (this.nodeName == 'H2')
{
if (i != 0) { newHtml += '</div></div>'; }
newHtml += '<div class="foldOutItem"><div class="foldOutItemTitle"><h2><a href="#"><img src="../images/footer-arrow.png" alt="" width="17" height="20" class="foldoutArrow" />' + $(this).html() + '</a></h2></div><div class="foldOutItemContent">';
} else {
newHtml += $(this).html();
}
});
newHtml += '</div></div>';
$('.foldOutEnabled').html(newHtml);
}
In my opinion this can be improved but it works except that the .html() strips all the html tags. So all the 'p' and 'h3' and what ever more tags the content contains are gone.
Now my question, how can i prevent this?
Upvotes: 2
Views: 1304
Reputation: 101
Using JavaScript you can do it like this.
let summ = 'your content here';
summ.split('/<h2>.*?<\/h2>/g');
result = summ.match(/<h2>(.*?)<\/h2>/g).map(function(val){
return val;
});
let data = [];
let preData = '';
for(var i =0; i < result.length; i++) {
const position = summ.indexOf(result[i]);
if (i === 0) {
if (position === 0) {
preData = '';
} else {
preData = summ.substr(0, position);
}
}
// Logic to find content and headers
const obj = {content: '', title: ''};
obj.title = result[i];
if (i === result.length - 1) {
obj.content = summ.substr(position + result[i].length, summ.length);
} else {
obj.content = summ.substr(position + result[i].length, summ.indexOf(result[i+1]));
}
data.push(obj);
}
Title will be the h2 tags and content will contain all the tags present between two h2 tags.
You can now loop over the array to create html structure of your choice.
Upvotes: 0
Reputation: 206111
Try this:
In the demo i coloured the new classes to help visualize the changes.
$('.foldOutEnabled h2').each(function(){
$(this).nextUntil('h2').andSelf().wrapAll('<div class="foldOutItem" />');
$(this).nextAll().wrapAll('<div class="foldOutItemContent" />')
.end().wrap('<div class="foldOutItemTitle" />');
});
http://api.jquery.com/each/
http://api.jquery.com/nextuntil/
http://api.jquery.com/andself/
http://api.jquery.com/wrapall/
http://api.jquery.com/nextall/
http://api.jquery.com/end/
Upvotes: 2