Skip to content

Commit cd4a4d9

Browse files
5saviahvfb55
andauthored
.wrapAll API method (#1590)
Co-authored-by: 5saviahv <[email protected]> Co-authored-by: Felix Böhm <[email protected]>
1 parent e8f5e98 commit cd4a4d9

File tree

4 files changed

+162
-1
lines changed

4 files changed

+162
-1
lines changed

lib/api/forms.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ exports.serialize = function () {
3535
*
3636
* @see {@link http://api.jquery.com/serializeArray/}
3737
*
38-
* @returns {Array<object<string,string>>} The serialized form.
38+
* @returns {object[]} The serialized form.
3939
*/
4040
exports.serializeArray = function () {
4141
// Resolve all form elements from either forms or collections of form elements

lib/api/manipulation.js

+80
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,86 @@ exports.wrapInner = _wrap(function (el, elInsertLocation, wrapperDom) {
360360
updateDOM(wrapperDom, el);
361361
});
362362

363+
/**
364+
* The .wrapAll() function can take any string or object that could be passed to
365+
* the $() function to specify a DOM structure. This structure may be nested
366+
* several levels deep, but should contain only one inmost element. The
367+
* structure will be wrapped around all of the elements in the set of matched
368+
* elements, as a single group.
369+
*
370+
* @example <caption>With markup passed to `wrapAll`</caption>
371+
* const $ = cheerio.load(
372+
* '<div class="container"><div class="inner">First</div><div class="inner">Second</div></div>'
373+
* );
374+
* $('.inner').wrapAll("<div class='new'></div>");
375+
*
376+
* //=> <div class="container">
377+
* // <div class='new'>
378+
* // <div class="inner">First</div>
379+
* // <div class="inner">Second</div>
380+
* // </div>
381+
* // </div>
382+
*
383+
* @example <caption>With an existing cheerio instance</caption>
384+
* const $ = cheerio.load(
385+
* '<span>Span 1</span><strong>Strong</strong><span>Span 2</span>'
386+
* );
387+
* const wrap = $('<div><p><em><b></b></em></p></div>');
388+
* $('span').wrapAll(wrap);
389+
*
390+
* //=> <div>
391+
* // <p>
392+
* // <em>
393+
* // <b>
394+
* // <span>Span 1</span>
395+
* // <span>Span 2</span>
396+
* // </b>
397+
* // </em>
398+
* // </p>
399+
* // </div>
400+
* // <strong>Strong</strong>
401+
*
402+
* @param {Cheerio} wrapper - The DOM structure to wrap around all matched
403+
* elements in the selection.
404+
* @see {@link https://api.jquery.com/wrapAll/}
405+
* @returns {Cheerio} The instance itself.
406+
*/
407+
exports.wrapAll = function (wrapper) {
408+
if (this[0]) {
409+
if (typeof wrapper === 'function') {
410+
wrapper = wrapper.call(this[0]);
411+
}
412+
413+
var wrap = this._make(wrapper);
414+
415+
if (this[0].parent) {
416+
wrap = wrap.insertBefore(this[0]);
417+
}
418+
419+
// if html is given as wrapper, wrap may contain text elements
420+
var elInsertLocation = { children: wrap };
421+
var j = 0;
422+
423+
// Find the deepest child. Only consider the first tag child of each node
424+
// (ignore text); stop if no children are found.
425+
while (
426+
elInsertLocation &&
427+
elInsertLocation.children &&
428+
j >= elInsertLocation.children.length
429+
) {
430+
if (elInsertLocation.children[j].type === 'tag') {
431+
elInsertLocation = elInsertLocation.children[j];
432+
j = 0;
433+
} else {
434+
j++;
435+
}
436+
}
437+
438+
this._make(elInsertLocation).append(this);
439+
}
440+
return this;
441+
};
442+
363443
/**
364444
* Insert content next to each element in the set of matched elements.
365445
*

test/api/manipulation.js

+67
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var expect = require('expect.js');
22
var cheerio = require('../..');
33
var fruits = require('../fixtures').fruits;
4+
var divcontainers = require('../fixtures').divcontainers;
45
var toArray = Function.call.bind(Array.prototype.slice);
56

67
describe('$(...)', function () {
@@ -318,6 +319,72 @@ describe('$(...)', function () {
318319
});
319320
});
320321

322+
describe('.wrapAll', function () {
323+
var doc;
324+
var $inner;
325+
326+
beforeEach(function () {
327+
doc = cheerio.load(divcontainers);
328+
$inner = doc('.inner');
329+
});
330+
331+
it('(Cheerio object) : should insert the element and wrap elements with it', function () {
332+
$inner.wrapAll(doc('#new'));
333+
var $container = doc('.container');
334+
var $wrap = doc('b');
335+
336+
expect($container).to.have.length(2);
337+
expect($container[0].children).to.have.length(1);
338+
expect($container[1].children).to.have.length(0);
339+
expect($container[0].children[0]).to.be(doc('#new')[0]);
340+
341+
expect($inner).to.have.length(4);
342+
expect($wrap[0].children).to.have.length(4);
343+
expect($inner[0].parent).to.be($wrap[0]);
344+
expect($inner[1].parent).to.be($wrap[0]);
345+
expect($inner[2].parent).to.be($wrap[0]);
346+
expect($inner[3].parent).to.be($wrap[0]);
347+
});
348+
349+
it('(html) : should wrap elements with it', function () {
350+
$inner.wrapAll('<div class="wrap"></div>');
351+
var $container = doc('.container');
352+
var $wrap = doc('.wrap');
353+
354+
expect($inner).to.have.length(4);
355+
expect($container).to.have.length(2);
356+
expect($wrap).to.have.length(1);
357+
expect($wrap[0].children).to.have.length(4);
358+
expect($container[0].children).to.have.length(1);
359+
expect($container[1].children).to.have.length(0);
360+
expect($inner[0].parent).to.be($wrap[0]);
361+
expect($inner[1].parent).to.be($wrap[0]);
362+
expect($inner[2].parent).to.be($wrap[0]);
363+
expect($inner[3].parent).to.be($wrap[0]);
364+
expect($wrap[0].parent).to.be($container[0]);
365+
expect($container[0].children[0]).to.be($wrap[0]);
366+
});
367+
368+
it('(selector) : should find element from dom, wrap elements with it', function () {
369+
$inner.wrapAll('#new');
370+
var $container = doc('.container');
371+
var $wrap = doc('b');
372+
var $new = doc('#new');
373+
374+
expect($inner).to.have.length(4);
375+
expect($container).to.have.length(2);
376+
expect($container[0].children).to.have.length(1);
377+
expect($container[1].children).to.have.length(0);
378+
expect($wrap[0].children).to.have.length(4);
379+
expect($inner[0].parent).to.be($wrap[0]);
380+
expect($inner[1].parent).to.be($wrap[0]);
381+
expect($inner[2].parent).to.be($wrap[0]);
382+
expect($inner[3].parent).to.be($wrap[0]);
383+
expect($new[0].parent).to.be($container[0]);
384+
expect($container[0].children[0]).to.be($new[0]);
385+
});
386+
});
387+
321388
describe('.append', function () {
322389
it('() : should do nothing', function () {
323390
expect($('#fruits').append()[0].tagName).to.equal('ul');

test/fixtures.js

+14
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ exports.vegetables = [
1414
'</ul>',
1515
].join('');
1616

17+
exports.divcontainers = [
18+
'<div class="container">',
19+
'<div class="inner">First</div>',
20+
'<div class="inner">Second</div>',
21+
'</div>',
22+
'<div class="container">',
23+
'<div class="inner">Third</div>',
24+
'<div class="inner">Fourth</div>',
25+
'</div>',
26+
'<div id="new"><div>',
27+
'<div><p><em><b></b></em></p></div>',
28+
'</div>',
29+
].join('');
30+
1731
exports.chocolates = [
1832
'<ul id="chocolates">',
1933
'<li class="linth" data-highlight="Lindor" data-origin="swiss">Linth</li>',

0 commit comments

Comments
 (0)