From cd4a4d9515eb8455b649cebf9a520f62b2a66b3b Mon Sep 17 00:00:00 2001 From: 5saviahv <49443574+5saviahv@users.noreply.github.com> Date: Fri, 25 Dec 2020 22:36:25 +0200 Subject: [PATCH] .wrapAll API method (#1590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 5saviahv <5saviahv@users.noreply.github.com> Co-authored-by: Felix Böhm --- lib/api/forms.js | 2 +- lib/api/manipulation.js | 80 ++++++++++++++++++++++++++++++++++++++++ test/api/manipulation.js | 67 +++++++++++++++++++++++++++++++++ test/fixtures.js | 14 +++++++ 4 files changed, 162 insertions(+), 1 deletion(-) diff --git a/lib/api/forms.js b/lib/api/forms.js index 496a4b5694..4bb99141d2 100644 --- a/lib/api/forms.js +++ b/lib/api/forms.js @@ -35,7 +35,7 @@ exports.serialize = function () { * * @see {@link http://api.jquery.com/serializeArray/} * - * @returns {Array>} The serialized form. + * @returns {object[]} The serialized form. */ exports.serializeArray = function () { // Resolve all form elements from either forms or collections of form elements diff --git a/lib/api/manipulation.js b/lib/api/manipulation.js index ceaedd04d7..a63a28ad95 100644 --- a/lib/api/manipulation.js +++ b/lib/api/manipulation.js @@ -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 With markup passed to `wrapAll` + * const $ = cheerio.load( + * '
First
Second
' + * ); + * $('.inner').wrapAll("
"); + * + * //=>
+ * //
+ * //
First
+ * //
Second
+ * //
+ * //
+ * + * @example With an existing cheerio instance + * const $ = cheerio.load( + * 'Span 1StrongSpan 2' + * ); + * const wrap = $('

'); + * $('span').wrapAll(wrap); + * + * //=>
+ * //

+ * // + * // + * // Span 1 + * // Span 2 + * // + * // + * //

+ * //
+ * // 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. * diff --git a/test/api/manipulation.js b/test/api/manipulation.js index ca239723b0..7108f1d5fb 100644 --- a/test/api/manipulation.js +++ b/test/api/manipulation.js @@ -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 () { @@ -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('
'); + 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'); diff --git a/test/fixtures.js b/test/fixtures.js index b9d09afb63..5901bec9a4 100644 --- a/test/fixtures.js +++ b/test/fixtures.js @@ -14,6 +14,20 @@ exports.vegetables = [ '', ].join(''); +exports.divcontainers = [ + '
', + '
First
', + '
Second
', + '
', + '
', + '
Third
', + '
Fourth
', + '
', + '
', + '

', + '
', +].join(''); + exports.chocolates = [ '
    ', '
  • Linth
  • ',