Skip to content

Commit

Permalink
.wrapAll API method (#1590)
Browse files Browse the repository at this point in the history
Co-authored-by: 5saviahv <[email protected]>
Co-authored-by: Felix Böhm <[email protected]>
  • Loading branch information
3 people authored Dec 25, 2020
1 parent e8f5e98 commit cd4a4d9
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/api/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ exports.serialize = function () {
*
* @see {@link http://api.jquery.com/serializeArray/}
*
* @returns {Array<object<string,string>>} The serialized form.
* @returns {object[]} The serialized form.
*/
exports.serializeArray = function () {
// Resolve all form elements from either forms or collections of form elements
Expand Down
80 changes: 80 additions & 0 deletions lib/api/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,86 @@ exports.wrapInner = _wrap(function (el, elInsertLocation, wrapperDom) {
updateDOM(wrapperDom, el);
});

/**
* The .wrapAll() function can take any string or object that could be passed to
* the $() function to specify a DOM structure. This structure may be nested
* several levels deep, but should contain only one inmost element. The
* structure will be wrapped around all of the elements in the set of matched
* elements, as a single group.
*
* @example <caption>With markup passed to `wrapAll`</caption>
* const $ = cheerio.load(
* '<div class="container"><div class="inner">First</div><div class="inner">Second</div></div>'
* );
* $('.inner').wrapAll("<div class='new'></div>");
*
* //=> <div class="container">
* // <div class='new'>
* // <div class="inner">First</div>
* // <div class="inner">Second</div>
* // </div>
* // </div>
*
* @example <caption>With an existing cheerio instance</caption>
* const $ = cheerio.load(
* '<span>Span 1</span><strong>Strong</strong><span>Span 2</span>'
* );
* const wrap = $('<div><p><em><b></b></em></p></div>');
* $('span').wrapAll(wrap);
*
* //=> <div>
* // <p>
* // <em>
* // <b>
* // <span>Span 1</span>
* // <span>Span 2</span>
* // </b>
* // </em>
* // </p>
* // </div>
* // <strong>Strong</strong>
*
* @param {Cheerio} wrapper - The DOM structure to wrap around all matched
* elements in the selection.
* @see {@link https://api.jquery.com/wrapAll/}
* @returns {Cheerio} The instance itself.
*/
exports.wrapAll = function (wrapper) {
if (this[0]) {
if (typeof wrapper === 'function') {
wrapper = wrapper.call(this[0]);
}

var wrap = this._make(wrapper);

if (this[0].parent) {
wrap = wrap.insertBefore(this[0]);
}

// if html is given as wrapper, wrap may contain text elements
var elInsertLocation = { children: wrap };
var j = 0;

// Find the deepest child. Only consider the first tag child of each node
// (ignore text); stop if no children are found.
while (
elInsertLocation &&
elInsertLocation.children &&
j >= elInsertLocation.children.length
) {
if (elInsertLocation.children[j].type === 'tag') {
elInsertLocation = elInsertLocation.children[j];
j = 0;
} else {
j++;
}
}

this._make(elInsertLocation).append(this);
}
return this;
};

/**
* Insert content next to each element in the set of matched elements.
*
Expand Down
67 changes: 67 additions & 0 deletions test/api/manipulation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
var expect = require('expect.js');
var cheerio = require('../..');
var fruits = require('../fixtures').fruits;
var divcontainers = require('../fixtures').divcontainers;
var toArray = Function.call.bind(Array.prototype.slice);

describe('$(...)', function () {
Expand Down Expand Up @@ -318,6 +319,72 @@ describe('$(...)', function () {
});
});

describe('.wrapAll', function () {
var doc;
var $inner;

beforeEach(function () {
doc = cheerio.load(divcontainers);
$inner = doc('.inner');
});

it('(Cheerio object) : should insert the element and wrap elements with it', function () {
$inner.wrapAll(doc('#new'));
var $container = doc('.container');
var $wrap = doc('b');

expect($container).to.have.length(2);
expect($container[0].children).to.have.length(1);
expect($container[1].children).to.have.length(0);
expect($container[0].children[0]).to.be(doc('#new')[0]);

expect($inner).to.have.length(4);
expect($wrap[0].children).to.have.length(4);
expect($inner[0].parent).to.be($wrap[0]);
expect($inner[1].parent).to.be($wrap[0]);
expect($inner[2].parent).to.be($wrap[0]);
expect($inner[3].parent).to.be($wrap[0]);
});

it('(html) : should wrap elements with it', function () {
$inner.wrapAll('<div class="wrap"></div>');
var $container = doc('.container');
var $wrap = doc('.wrap');

expect($inner).to.have.length(4);
expect($container).to.have.length(2);
expect($wrap).to.have.length(1);
expect($wrap[0].children).to.have.length(4);
expect($container[0].children).to.have.length(1);
expect($container[1].children).to.have.length(0);
expect($inner[0].parent).to.be($wrap[0]);
expect($inner[1].parent).to.be($wrap[0]);
expect($inner[2].parent).to.be($wrap[0]);
expect($inner[3].parent).to.be($wrap[0]);
expect($wrap[0].parent).to.be($container[0]);
expect($container[0].children[0]).to.be($wrap[0]);
});

it('(selector) : should find element from dom, wrap elements with it', function () {
$inner.wrapAll('#new');
var $container = doc('.container');
var $wrap = doc('b');
var $new = doc('#new');

expect($inner).to.have.length(4);
expect($container).to.have.length(2);
expect($container[0].children).to.have.length(1);
expect($container[1].children).to.have.length(0);
expect($wrap[0].children).to.have.length(4);
expect($inner[0].parent).to.be($wrap[0]);
expect($inner[1].parent).to.be($wrap[0]);
expect($inner[2].parent).to.be($wrap[0]);
expect($inner[3].parent).to.be($wrap[0]);
expect($new[0].parent).to.be($container[0]);
expect($container[0].children[0]).to.be($new[0]);
});
});

describe('.append', function () {
it('() : should do nothing', function () {
expect($('#fruits').append()[0].tagName).to.equal('ul');
Expand Down
14 changes: 14 additions & 0 deletions test/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ exports.vegetables = [
'</ul>',
].join('');

exports.divcontainers = [
'<div class="container">',
'<div class="inner">First</div>',
'<div class="inner">Second</div>',
'</div>',
'<div class="container">',
'<div class="inner">Third</div>',
'<div class="inner">Fourth</div>',
'</div>',
'<div id="new"><div>',
'<div><p><em><b></b></em></p></div>',
'</div>',
].join('');

exports.chocolates = [
'<ul id="chocolates">',
'<li class="linth" data-highlight="Lindor" data-origin="swiss">Linth</li>',
Expand Down

0 comments on commit cd4a4d9

Please sign in to comment.