0

So I'm having a small problem wrapping my HTML using jQuery from one <h2> tag to another <h2>

This is quite similar to this, but the solution is not the same. jQuery: How to select "from here until the next H2"?

My problem is, that I want to wrap these elements as a whole.

Here is my HTML as an example.

<div class="info-hold">
    <h2>Lorem</h2>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
    <h2>Lorem 2</h2>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
    <h2>Lorem 3</h2>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
</div>

Here is what I want to achieve:

<div class="info-hold">
    <h2>Lorem</h2>
    <div class="info-wrapper">
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
    </div>
    <h2>Lorem 2</h2>
    <div class="info-wrapper">
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
    </div>
    <h2>Lorem 3</h2>
    <div class="info-wrapper">
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
        <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
    </div>
</div>

The html is there and I cannot modify it, I need a jQuery solution for this.

Thanks.

This is not a duplicate, since the problem is different!

Community
  • 1
  • 1
Andrejs Gubars
  • 584
  • 7
  • 30

3 Answers3

3

use nextUtil then wrapAll

$('h2').each(function(){
  $(this).nextUntil('h2').wrapAll($('<div>', { class:'info-wrapper' }))
})
.info-wrapper{
  border:1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="info-hold">
  <h2>Lorem</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
  <h2>Lorem 2</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
  <h2>Lorem 3</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
</div>
BenG
  • 14,826
  • 5
  • 45
  • 60
2

You can use this following code : Loop over every h2, find the next three element, wrap them all.

$.each($(".info-hold").find("h2"), function() {

    $(this).nextAll().slice(0, 3).wrapAll('<div class="info-wrapper">');

})

Live Demo JSFIDDLE

Jax Teller
  • 1,447
  • 2
  • 15
  • 24
1

While you've already accepted an answer, I thought – if only for completion – that I'd take a moment and offer a way to achieve your requirements using only plain JavaScript, albeit using mostly ES6, which requires up-to-date browsers:

function wrapAll(opts) {
  // setting the defaults for the function:
  var settings = {
    // the element-node from which to begin wrapping:
    'wrapFrom': null,

    // a CSS selector to define the element before
    // which wrapping should stop:
    'wrapTo': null,

    // the element-type to wrap with:
    'wrapWith': 'div',

    // the class - if any - to apply to the
    // wrapping element:
    'wrapClass': 'wrapper'
  };

  // using Object.keys() to iterate over the
  // opts Object (or an empty object-literal)
  // if no opts Object is supplied:
  Object.keys(opts || {}).forEach(function(key) {

    // updating the default settings with
    // the value held in the opts Object:
    settings[key] = opts[key];
  });

  // if there is no settings.wrapFrom node, or
  // no settings.wrapTo string:
  if (!settings.wrapFrom || !settings.wrapTo) {

    // we quit here:
    return false;
  }

  // creating the element with which we can wrap:
  var wrapper = document.createElement(settings.wrapWith),

    // creating an Array-literal for later use:
    classes = [];

  // if the settigns.wrapClass value is a string:
  if ('string' === typeof settings.wrapClass) {

    // we set classes to the value of the String,
    // after splitting it into an Array, using
    // String.prototype.split() and a regular
    // expression, by breaking it apart 
    // on sequences of one or more (+)
    // white-space characters (\s):
    classes = settings.wrapClass.split(/\s+/);

  // otherwise, if settings.wrapClass is an Array:
  } else if (settings.wrapClass instanceof Array) {

    // we pass the existing array to the
    // classes variable:
    classes = settings.wrapClass;
  }

  // here we iterate over the classes, using
  // Array.prototype.forEach():
  classes.forEach(function(cN) {
    // cN, the first argument, is a reference
    // to the current array-element (the class-name)
    // of the Array over which we're iterating.

    // here we use the Element.classList API to
    // add the class-name to the wrapper element,
    // after trimming away leading and trailing
    // white-space, using String.prototype.trim():
    wrapper.classList.add(cN.trim());
  });

  // here we navigate from the settings.wrapFrom
  // node to its parentNode, and insert the wrapper
  // Element before the next-sibling of the
  // settings.wrapFrom node:
  settings.wrapFrom.parentNode.insertBefore(wrapper, settings.wrapFrom.nextSibling);

  // while there is a next-sibling of the wrapper,
  // and either that next-sibling is not an element
  // (which has a nodeType of 1), or the next-sibling
  // is an element node and that element node does not
  // match the selector supplied in settings.wrapTo:
  while (wrapper.nextSibling && (wrapper.nextSibling.nodeType !== 1 || (wrapper.nextSibling.nodeType === 1 && !wrapper.nextSibling.matches(settings.wrapTo)))) {

    // we append the next-sibling to the
    // wrapper:
    wrapper.appendChild(wrapper.nextSibling);
  }

}

// here we retrieve an HTMLCollection using document.querySelectorAll,
// and convert that array-like HTMLCollection into an Array using
// Array.from; then using Array.prototype.forEach() to iterate over
// the Array of nodes, which then calls the wrapAll function:
Array.from(document.querySelectorAll('h2')).forEach(function(heading) {
  wrapAll({
    'wrapFrom': heading,
    'wrapTo': 'h2',
    'wrapClass': 'info-wrapper'
  });
});

function wrapAll(opts) {
  var settings = {
    'wrapFrom': null,
    'wrapTo': null,
    'wrapWith': 'div',
    'wrapClass': 'wrapper'
  };

  Object.keys(opts || {}).forEach(function(key) {
    settings[key] = opts[key];
  });

  if (!settings.wrapFrom || !settings.wrapTo) {
    return false;
  }

  var wrapper = document.createElement(settings.wrapWith),
    collection = [],
    classes = [];

  if ('string' === typeof settings.wrapClass) {
    classes = settings.wrapClass.split(/\s+/);
  } else if (settings.wrapClass instanceof Array) {
    classes = settings.wrapClass;
  }

  classes.forEach(function(cN) {
    wrapper.classList.add(cN.trim());
  });

  settings.wrapFrom.parentNode.insertBefore(wrapper, settings.wrapFrom.nextSibling);

  while (wrapper.nextSibling && (wrapper.nextSibling.nodeType !== 1 || (wrapper.nextSibling.nodeType === 1 && !wrapper.nextSibling.matches(settings.wrapTo)))) {
    wrapper.appendChild(wrapper.nextSibling);
  }

}

Array.from(document.querySelectorAll('h2')).forEach(function(heading) {
  wrapAll({
    'wrapFrom': heading,
    'wrapTo': 'h2',
    'wrapClass': 'info-wrapper'
  });
});
.info-wrapper {
  border: 1px solid red;
}
<div class="info-hold">
  <h2>Lorem</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
  <h2>Lorem 2</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
  <h2>Lorem 3</h2>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sequi dolore quae, quas ipsum illo magni vero quaerat quam ipsam iste autem quisquam, aperiam laudantium cumque, porro amet! Sint ipsa, laborum!</p>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tenetur ab officiis nostrum modi aliquam, rem dicta deleniti provident sunt, libero nobis ea adipisci praesentium dolore fuga nesciunt iure at maiores!</p>
</div>

JS Fiddle demo.

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410