manipulation.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. "use strict";
  2. /**
  3. * Methods for modifying the DOM structure.
  4. *
  5. * @module cheerio/manipulation
  6. */
  7. var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
  8. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  9. if (ar || !(i in from)) {
  10. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  11. ar[i] = from[i];
  12. }
  13. }
  14. return to.concat(ar || Array.prototype.slice.call(from));
  15. };
  16. Object.defineProperty(exports, "__esModule", { value: true });
  17. exports.clone = exports.text = exports.toString = exports.html = exports.empty = exports.replaceWith = exports.remove = exports.insertBefore = exports.before = exports.insertAfter = exports.after = exports.wrapAll = exports.unwrap = exports.wrapInner = exports.wrap = exports.prepend = exports.append = exports.prependTo = exports.appendTo = exports._makeDomArray = void 0;
  18. var domhandler_1 = require("domhandler");
  19. var parse_js_1 = require("../parse.js");
  20. var static_js_1 = require("../static.js");
  21. var utils_js_1 = require("../utils.js");
  22. var domutils_1 = require("domutils");
  23. /**
  24. * Create an array of nodes, recursing into arrays and parsing strings if necessary.
  25. *
  26. * @private
  27. * @category Manipulation
  28. * @param elem - Elements to make an array of.
  29. * @param clone - Optionally clone nodes.
  30. * @returns The array of nodes.
  31. */
  32. function _makeDomArray(elem, clone) {
  33. var _this = this;
  34. if (elem == null) {
  35. return [];
  36. }
  37. if ((0, utils_js_1.isCheerio)(elem)) {
  38. return clone ? (0, utils_js_1.cloneDom)(elem.get()) : elem.get();
  39. }
  40. if (Array.isArray(elem)) {
  41. return elem.reduce(function (newElems, el) { return newElems.concat(_this._makeDomArray(el, clone)); }, []);
  42. }
  43. if (typeof elem === 'string') {
  44. return this._parse(elem, this.options, false, null).children;
  45. }
  46. return clone ? (0, utils_js_1.cloneDom)([elem]) : [elem];
  47. }
  48. exports._makeDomArray = _makeDomArray;
  49. function _insert(concatenator) {
  50. return function () {
  51. var _this = this;
  52. var elems = [];
  53. for (var _i = 0; _i < arguments.length; _i++) {
  54. elems[_i] = arguments[_i];
  55. }
  56. var lastIdx = this.length - 1;
  57. return (0, utils_js_1.domEach)(this, function (el, i) {
  58. if (!(0, domhandler_1.hasChildren)(el))
  59. return;
  60. var domSrc = typeof elems[0] === 'function'
  61. ? elems[0].call(el, i, _this._render(el.children))
  62. : elems;
  63. var dom = _this._makeDomArray(domSrc, i < lastIdx);
  64. concatenator(dom, el.children, el);
  65. });
  66. };
  67. }
  68. /**
  69. * Modify an array in-place, removing some number of elements and adding new
  70. * elements directly following them.
  71. *
  72. * @private
  73. * @category Manipulation
  74. * @param array - Target array to splice.
  75. * @param spliceIdx - Index at which to begin changing the array.
  76. * @param spliceCount - Number of elements to remove from the array.
  77. * @param newElems - Elements to insert into the array.
  78. * @param parent - The parent of the node.
  79. * @returns The spliced array.
  80. */
  81. function uniqueSplice(array, spliceIdx, spliceCount, newElems, parent) {
  82. var _a, _b;
  83. var spliceArgs = __spreadArray([
  84. spliceIdx,
  85. spliceCount
  86. ], newElems, true);
  87. var prev = spliceIdx === 0 ? null : array[spliceIdx - 1];
  88. var next = spliceIdx + spliceCount >= array.length
  89. ? null
  90. : array[spliceIdx + spliceCount];
  91. /*
  92. * Before splicing in new elements, ensure they do not already appear in the
  93. * current array.
  94. */
  95. for (var idx = 0; idx < newElems.length; ++idx) {
  96. var node = newElems[idx];
  97. var oldParent = node.parent;
  98. if (oldParent) {
  99. var oldSiblings = oldParent.children;
  100. var prevIdx = oldSiblings.indexOf(node);
  101. if (prevIdx > -1) {
  102. oldParent.children.splice(prevIdx, 1);
  103. if (parent === oldParent && spliceIdx > prevIdx) {
  104. spliceArgs[0]--;
  105. }
  106. }
  107. }
  108. node.parent = parent;
  109. if (node.prev) {
  110. node.prev.next = (_a = node.next) !== null && _a !== void 0 ? _a : null;
  111. }
  112. if (node.next) {
  113. node.next.prev = (_b = node.prev) !== null && _b !== void 0 ? _b : null;
  114. }
  115. node.prev = idx === 0 ? prev : newElems[idx - 1];
  116. node.next = idx === newElems.length - 1 ? next : newElems[idx + 1];
  117. }
  118. if (prev) {
  119. prev.next = newElems[0];
  120. }
  121. if (next) {
  122. next.prev = newElems[newElems.length - 1];
  123. }
  124. return array.splice.apply(array, spliceArgs);
  125. }
  126. /**
  127. * Insert every element in the set of matched elements to the end of the target.
  128. *
  129. * @category Manipulation
  130. * @example
  131. *
  132. * ```js
  133. * $('<li class="plum">Plum</li>').appendTo('#fruits');
  134. * $.html();
  135. * //=> <ul id="fruits">
  136. * // <li class="apple">Apple</li>
  137. * // <li class="orange">Orange</li>
  138. * // <li class="pear">Pear</li>
  139. * // <li class="plum">Plum</li>
  140. * // </ul>
  141. * ```
  142. *
  143. * @param target - Element to append elements to.
  144. * @returns The instance itself.
  145. * @see {@link https://api.jquery.com/appendTo/}
  146. */
  147. function appendTo(target) {
  148. var appendTarget = (0, utils_js_1.isCheerio)(target) ? target : this._make(target);
  149. appendTarget.append(this);
  150. return this;
  151. }
  152. exports.appendTo = appendTo;
  153. /**
  154. * Insert every element in the set of matched elements to the beginning of the target.
  155. *
  156. * @category Manipulation
  157. * @example
  158. *
  159. * ```js
  160. * $('<li class="plum">Plum</li>').prependTo('#fruits');
  161. * $.html();
  162. * //=> <ul id="fruits">
  163. * // <li class="plum">Plum</li>
  164. * // <li class="apple">Apple</li>
  165. * // <li class="orange">Orange</li>
  166. * // <li class="pear">Pear</li>
  167. * // </ul>
  168. * ```
  169. *
  170. * @param target - Element to prepend elements to.
  171. * @returns The instance itself.
  172. * @see {@link https://api.jquery.com/prependTo/}
  173. */
  174. function prependTo(target) {
  175. var prependTarget = (0, utils_js_1.isCheerio)(target) ? target : this._make(target);
  176. prependTarget.prepend(this);
  177. return this;
  178. }
  179. exports.prependTo = prependTo;
  180. /**
  181. * Inserts content as the _last_ child of each of the selected elements.
  182. *
  183. * @category Manipulation
  184. * @example
  185. *
  186. * ```js
  187. * $('ul').append('<li class="plum">Plum</li>');
  188. * $.html();
  189. * //=> <ul id="fruits">
  190. * // <li class="apple">Apple</li>
  191. * // <li class="orange">Orange</li>
  192. * // <li class="pear">Pear</li>
  193. * // <li class="plum">Plum</li>
  194. * // </ul>
  195. * ```
  196. *
  197. * @see {@link https://api.jquery.com/append/}
  198. */
  199. exports.append = _insert(function (dom, children, parent) {
  200. uniqueSplice(children, children.length, 0, dom, parent);
  201. });
  202. /**
  203. * Inserts content as the _first_ child of each of the selected elements.
  204. *
  205. * @category Manipulation
  206. * @example
  207. *
  208. * ```js
  209. * $('ul').prepend('<li class="plum">Plum</li>');
  210. * $.html();
  211. * //=> <ul id="fruits">
  212. * // <li class="plum">Plum</li>
  213. * // <li class="apple">Apple</li>
  214. * // <li class="orange">Orange</li>
  215. * // <li class="pear">Pear</li>
  216. * // </ul>
  217. * ```
  218. *
  219. * @see {@link https://api.jquery.com/prepend/}
  220. */
  221. exports.prepend = _insert(function (dom, children, parent) {
  222. uniqueSplice(children, 0, 0, dom, parent);
  223. });
  224. function _wrap(insert) {
  225. return function (wrapper) {
  226. var lastIdx = this.length - 1;
  227. var lastParent = this.parents().last();
  228. for (var i = 0; i < this.length; i++) {
  229. var el = this[i];
  230. var wrap_1 = typeof wrapper === 'function'
  231. ? wrapper.call(el, i, el)
  232. : typeof wrapper === 'string' && !(0, utils_js_1.isHtml)(wrapper)
  233. ? lastParent.find(wrapper).clone()
  234. : wrapper;
  235. var wrapperDom = this._makeDomArray(wrap_1, i < lastIdx)[0];
  236. if (!wrapperDom || !(0, domhandler_1.hasChildren)(wrapperDom))
  237. continue;
  238. var elInsertLocation = wrapperDom;
  239. /*
  240. * Find the deepest child. Only consider the first tag child of each node
  241. * (ignore text); stop if no children are found.
  242. */
  243. var j = 0;
  244. while (j < elInsertLocation.children.length) {
  245. var child = elInsertLocation.children[j];
  246. if ((0, utils_js_1.isTag)(child)) {
  247. elInsertLocation = child;
  248. j = 0;
  249. }
  250. else {
  251. j++;
  252. }
  253. }
  254. insert(el, elInsertLocation, [wrapperDom]);
  255. }
  256. return this;
  257. };
  258. }
  259. /**
  260. * The .wrap() function can take any string or object that could be passed to
  261. * the $() factory function to specify a DOM structure. This structure may be
  262. * nested several levels deep, but should contain only one inmost element. A
  263. * copy of this structure will be wrapped around each of the elements in the set
  264. * of matched elements. This method returns the original set of elements for
  265. * chaining purposes.
  266. *
  267. * @category Manipulation
  268. * @example
  269. *
  270. * ```js
  271. * const redFruit = $('<div class="red-fruit"></div>');
  272. * $('.apple').wrap(redFruit);
  273. *
  274. * //=> <ul id="fruits">
  275. * // <div class="red-fruit">
  276. * // <li class="apple">Apple</li>
  277. * // </div>
  278. * // <li class="orange">Orange</li>
  279. * // <li class="plum">Plum</li>
  280. * // </ul>
  281. *
  282. * const healthy = $('<div class="healthy"></div>');
  283. * $('li').wrap(healthy);
  284. *
  285. * //=> <ul id="fruits">
  286. * // <div class="healthy">
  287. * // <li class="apple">Apple</li>
  288. * // </div>
  289. * // <div class="healthy">
  290. * // <li class="orange">Orange</li>
  291. * // </div>
  292. * // <div class="healthy">
  293. * // <li class="plum">Plum</li>
  294. * // </div>
  295. * // </ul>
  296. * ```
  297. *
  298. * @param wrapper - The DOM structure to wrap around each element in the selection.
  299. * @see {@link https://api.jquery.com/wrap/}
  300. */
  301. exports.wrap = _wrap(function (el, elInsertLocation, wrapperDom) {
  302. var parent = el.parent;
  303. if (!parent)
  304. return;
  305. var siblings = parent.children;
  306. var index = siblings.indexOf(el);
  307. (0, parse_js_1.update)([el], elInsertLocation);
  308. /*
  309. * The previous operation removed the current element from the `siblings`
  310. * array, so the `dom` array can be inserted without removing any
  311. * additional elements.
  312. */
  313. uniqueSplice(siblings, index, 0, wrapperDom, parent);
  314. });
  315. /**
  316. * The .wrapInner() function can take any string or object that could be passed
  317. * to the $() factory function to specify a DOM structure. This structure may be
  318. * nested several levels deep, but should contain only one inmost element. The
  319. * structure will be wrapped around the content of each of the elements in the
  320. * set of matched elements.
  321. *
  322. * @category Manipulation
  323. * @example
  324. *
  325. * ```js
  326. * const redFruit = $('<div class="red-fruit"></div>');
  327. * $('.apple').wrapInner(redFruit);
  328. *
  329. * //=> <ul id="fruits">
  330. * // <li class="apple">
  331. * // <div class="red-fruit">Apple</div>
  332. * // </li>
  333. * // <li class="orange">Orange</li>
  334. * // <li class="pear">Pear</li>
  335. * // </ul>
  336. *
  337. * const healthy = $('<div class="healthy"></div>');
  338. * $('li').wrapInner(healthy);
  339. *
  340. * //=> <ul id="fruits">
  341. * // <li class="apple">
  342. * // <div class="healthy">Apple</div>
  343. * // </li>
  344. * // <li class="orange">
  345. * // <div class="healthy">Orange</div>
  346. * // </li>
  347. * // <li class="pear">
  348. * // <div class="healthy">Pear</div>
  349. * // </li>
  350. * // </ul>
  351. * ```
  352. *
  353. * @param wrapper - The DOM structure to wrap around the content of each element
  354. * in the selection.
  355. * @returns The instance itself, for chaining.
  356. * @see {@link https://api.jquery.com/wrapInner/}
  357. */
  358. exports.wrapInner = _wrap(function (el, elInsertLocation, wrapperDom) {
  359. if (!(0, domhandler_1.hasChildren)(el))
  360. return;
  361. (0, parse_js_1.update)(el.children, elInsertLocation);
  362. (0, parse_js_1.update)(wrapperDom, el);
  363. });
  364. /**
  365. * The .unwrap() function, removes the parents of the set of matched elements
  366. * from the DOM, leaving the matched elements in their place.
  367. *
  368. * @category Manipulation
  369. * @example <caption>without selector</caption>
  370. *
  371. * ```js
  372. * const $ = cheerio.load(
  373. * '<div id=test>\n <div><p>Hello</p></div>\n <div><p>World</p></div>\n</div>'
  374. * );
  375. * $('#test p').unwrap();
  376. *
  377. * //=> <div id=test>
  378. * // <p>Hello</p>
  379. * // <p>World</p>
  380. * // </div>
  381. * ```
  382. *
  383. * @example <caption>with selector</caption>
  384. *
  385. * ```js
  386. * const $ = cheerio.load(
  387. * '<div id=test>\n <p>Hello</p>\n <b><p>World</p></b>\n</div>'
  388. * );
  389. * $('#test p').unwrap('b');
  390. *
  391. * //=> <div id=test>
  392. * // <p>Hello</p>
  393. * // <p>World</p>
  394. * // </div>
  395. * ```
  396. *
  397. * @param selector - A selector to check the parent element against. If an
  398. * element's parent does not match the selector, the element won't be unwrapped.
  399. * @returns The instance itself, for chaining.
  400. * @see {@link https://api.jquery.com/unwrap/}
  401. */
  402. function unwrap(selector) {
  403. var _this = this;
  404. this.parent(selector)
  405. .not('body')
  406. .each(function (_, el) {
  407. _this._make(el).replaceWith(el.children);
  408. });
  409. return this;
  410. }
  411. exports.unwrap = unwrap;
  412. /**
  413. * The .wrapAll() function can take any string or object that could be passed to
  414. * the $() function to specify a DOM structure. This structure may be nested
  415. * several levels deep, but should contain only one inmost element. The
  416. * structure will be wrapped around all of the elements in the set of matched
  417. * elements, as a single group.
  418. *
  419. * @category Manipulation
  420. * @example <caption>With markup passed to `wrapAll`</caption>
  421. *
  422. * ```js
  423. * const $ = cheerio.load(
  424. * '<div class="container"><div class="inner">First</div><div class="inner">Second</div></div>'
  425. * );
  426. * $('.inner').wrapAll("<div class='new'></div>");
  427. *
  428. * //=> <div class="container">
  429. * // <div class='new'>
  430. * // <div class="inner">First</div>
  431. * // <div class="inner">Second</div>
  432. * // </div>
  433. * // </div>
  434. * ```
  435. *
  436. * @example <caption>With an existing cheerio instance</caption>
  437. *
  438. * ```js
  439. * const $ = cheerio.load(
  440. * '<span>Span 1</span><strong>Strong</strong><span>Span 2</span>'
  441. * );
  442. * const wrap = $('<div><p><em><b></b></em></p></div>');
  443. * $('span').wrapAll(wrap);
  444. *
  445. * //=> <div>
  446. * // <p>
  447. * // <em>
  448. * // <b>
  449. * // <span>Span 1</span>
  450. * // <span>Span 2</span>
  451. * // </b>
  452. * // </em>
  453. * // </p>
  454. * // </div>
  455. * // <strong>Strong</strong>
  456. * ```
  457. *
  458. * @param wrapper - The DOM structure to wrap around all matched elements in the
  459. * selection.
  460. * @returns The instance itself.
  461. * @see {@link https://api.jquery.com/wrapAll/}
  462. */
  463. function wrapAll(wrapper) {
  464. var el = this[0];
  465. if (el) {
  466. var wrap_2 = this._make(typeof wrapper === 'function' ? wrapper.call(el, 0, el) : wrapper).insertBefore(el);
  467. // If html is given as wrapper, wrap may contain text elements
  468. var elInsertLocation = void 0;
  469. for (var i = 0; i < wrap_2.length; i++) {
  470. if (wrap_2[i].type === 'tag')
  471. elInsertLocation = wrap_2[i];
  472. }
  473. var j = 0;
  474. /*
  475. * Find the deepest child. Only consider the first tag child of each node
  476. * (ignore text); stop if no children are found.
  477. */
  478. while (elInsertLocation && j < elInsertLocation.children.length) {
  479. var child = elInsertLocation.children[j];
  480. if (child.type === 'tag') {
  481. elInsertLocation = child;
  482. j = 0;
  483. }
  484. else {
  485. j++;
  486. }
  487. }
  488. if (elInsertLocation)
  489. this._make(elInsertLocation).append(this);
  490. }
  491. return this;
  492. }
  493. exports.wrapAll = wrapAll;
  494. /* eslint-disable jsdoc/check-param-names*/
  495. /**
  496. * Insert content next to each element in the set of matched elements.
  497. *
  498. * @category Manipulation
  499. * @example
  500. *
  501. * ```js
  502. * $('.apple').after('<li class="plum">Plum</li>');
  503. * $.html();
  504. * //=> <ul id="fruits">
  505. * // <li class="apple">Apple</li>
  506. * // <li class="plum">Plum</li>
  507. * // <li class="orange">Orange</li>
  508. * // <li class="pear">Pear</li>
  509. * // </ul>
  510. * ```
  511. *
  512. * @param content - HTML string, DOM element, array of DOM elements or Cheerio
  513. * to insert after each element in the set of matched elements.
  514. * @returns The instance itself.
  515. * @see {@link https://api.jquery.com/after/}
  516. */
  517. function after() {
  518. var _this = this;
  519. var elems = [];
  520. for (var _i = 0; _i < arguments.length; _i++) {
  521. elems[_i] = arguments[_i];
  522. }
  523. var lastIdx = this.length - 1;
  524. return (0, utils_js_1.domEach)(this, function (el, i) {
  525. var parent = el.parent;
  526. if (!(0, domhandler_1.hasChildren)(el) || !parent) {
  527. return;
  528. }
  529. var siblings = parent.children;
  530. var index = siblings.indexOf(el);
  531. // If not found, move on
  532. /* istanbul ignore next */
  533. if (index < 0)
  534. return;
  535. var domSrc = typeof elems[0] === 'function'
  536. ? elems[0].call(el, i, _this._render(el.children))
  537. : elems;
  538. var dom = _this._makeDomArray(domSrc, i < lastIdx);
  539. // Add element after `this` element
  540. uniqueSplice(siblings, index + 1, 0, dom, parent);
  541. });
  542. }
  543. exports.after = after;
  544. /* eslint-enable jsdoc/check-param-names*/
  545. /**
  546. * Insert every element in the set of matched elements after the target.
  547. *
  548. * @category Manipulation
  549. * @example
  550. *
  551. * ```js
  552. * $('<li class="plum">Plum</li>').insertAfter('.apple');
  553. * $.html();
  554. * //=> <ul id="fruits">
  555. * // <li class="apple">Apple</li>
  556. * // <li class="plum">Plum</li>
  557. * // <li class="orange">Orange</li>
  558. * // <li class="pear">Pear</li>
  559. * // </ul>
  560. * ```
  561. *
  562. * @param target - Element to insert elements after.
  563. * @returns The set of newly inserted elements.
  564. * @see {@link https://api.jquery.com/insertAfter/}
  565. */
  566. function insertAfter(target) {
  567. var _this = this;
  568. if (typeof target === 'string') {
  569. target = this._make(target);
  570. }
  571. this.remove();
  572. var clones = [];
  573. this._makeDomArray(target).forEach(function (el) {
  574. var clonedSelf = _this.clone().toArray();
  575. var parent = el.parent;
  576. if (!parent) {
  577. return;
  578. }
  579. var siblings = parent.children;
  580. var index = siblings.indexOf(el);
  581. // If not found, move on
  582. /* istanbul ignore next */
  583. if (index < 0)
  584. return;
  585. // Add cloned `this` element(s) after target element
  586. uniqueSplice(siblings, index + 1, 0, clonedSelf, parent);
  587. clones.push.apply(clones, clonedSelf);
  588. });
  589. return this._make(clones);
  590. }
  591. exports.insertAfter = insertAfter;
  592. /* eslint-disable jsdoc/check-param-names*/
  593. /**
  594. * Insert content previous to each element in the set of matched elements.
  595. *
  596. * @category Manipulation
  597. * @example
  598. *
  599. * ```js
  600. * $('.apple').before('<li class="plum">Plum</li>');
  601. * $.html();
  602. * //=> <ul id="fruits">
  603. * // <li class="plum">Plum</li>
  604. * // <li class="apple">Apple</li>
  605. * // <li class="orange">Orange</li>
  606. * // <li class="pear">Pear</li>
  607. * // </ul>
  608. * ```
  609. *
  610. * @param content - HTML string, DOM element, array of DOM elements or Cheerio
  611. * to insert before each element in the set of matched elements.
  612. * @returns The instance itself.
  613. * @see {@link https://api.jquery.com/before/}
  614. */
  615. function before() {
  616. var _this = this;
  617. var elems = [];
  618. for (var _i = 0; _i < arguments.length; _i++) {
  619. elems[_i] = arguments[_i];
  620. }
  621. var lastIdx = this.length - 1;
  622. return (0, utils_js_1.domEach)(this, function (el, i) {
  623. var parent = el.parent;
  624. if (!(0, domhandler_1.hasChildren)(el) || !parent) {
  625. return;
  626. }
  627. var siblings = parent.children;
  628. var index = siblings.indexOf(el);
  629. // If not found, move on
  630. /* istanbul ignore next */
  631. if (index < 0)
  632. return;
  633. var domSrc = typeof elems[0] === 'function'
  634. ? elems[0].call(el, i, _this._render(el.children))
  635. : elems;
  636. var dom = _this._makeDomArray(domSrc, i < lastIdx);
  637. // Add element before `el` element
  638. uniqueSplice(siblings, index, 0, dom, parent);
  639. });
  640. }
  641. exports.before = before;
  642. /* eslint-enable jsdoc/check-param-names*/
  643. /**
  644. * Insert every element in the set of matched elements before the target.
  645. *
  646. * @category Manipulation
  647. * @example
  648. *
  649. * ```js
  650. * $('<li class="plum">Plum</li>').insertBefore('.apple');
  651. * $.html();
  652. * //=> <ul id="fruits">
  653. * // <li class="plum">Plum</li>
  654. * // <li class="apple">Apple</li>
  655. * // <li class="orange">Orange</li>
  656. * // <li class="pear">Pear</li>
  657. * // </ul>
  658. * ```
  659. *
  660. * @param target - Element to insert elements before.
  661. * @returns The set of newly inserted elements.
  662. * @see {@link https://api.jquery.com/insertBefore/}
  663. */
  664. function insertBefore(target) {
  665. var _this = this;
  666. var targetArr = this._make(target);
  667. this.remove();
  668. var clones = [];
  669. (0, utils_js_1.domEach)(targetArr, function (el) {
  670. var clonedSelf = _this.clone().toArray();
  671. var parent = el.parent;
  672. if (!parent) {
  673. return;
  674. }
  675. var siblings = parent.children;
  676. var index = siblings.indexOf(el);
  677. // If not found, move on
  678. /* istanbul ignore next */
  679. if (index < 0)
  680. return;
  681. // Add cloned `this` element(s) after target element
  682. uniqueSplice(siblings, index, 0, clonedSelf, parent);
  683. clones.push.apply(clones, clonedSelf);
  684. });
  685. return this._make(clones);
  686. }
  687. exports.insertBefore = insertBefore;
  688. /**
  689. * Removes the set of matched elements from the DOM and all their children.
  690. * `selector` filters the set of matched elements to be removed.
  691. *
  692. * @category Manipulation
  693. * @example
  694. *
  695. * ```js
  696. * $('.pear').remove();
  697. * $.html();
  698. * //=> <ul id="fruits">
  699. * // <li class="apple">Apple</li>
  700. * // <li class="orange">Orange</li>
  701. * // </ul>
  702. * ```
  703. *
  704. * @param selector - Optional selector for elements to remove.
  705. * @returns The instance itself.
  706. * @see {@link https://api.jquery.com/remove/}
  707. */
  708. function remove(selector) {
  709. // Filter if we have selector
  710. var elems = selector ? this.filter(selector) : this;
  711. (0, utils_js_1.domEach)(elems, function (el) {
  712. (0, domutils_1.removeElement)(el);
  713. el.prev = el.next = el.parent = null;
  714. });
  715. return this;
  716. }
  717. exports.remove = remove;
  718. /**
  719. * Replaces matched elements with `content`.
  720. *
  721. * @category Manipulation
  722. * @example
  723. *
  724. * ```js
  725. * const plum = $('<li class="plum">Plum</li>');
  726. * $('.pear').replaceWith(plum);
  727. * $.html();
  728. * //=> <ul id="fruits">
  729. * // <li class="apple">Apple</li>
  730. * // <li class="orange">Orange</li>
  731. * // <li class="plum">Plum</li>
  732. * // </ul>
  733. * ```
  734. *
  735. * @param content - Replacement for matched elements.
  736. * @returns The instance itself.
  737. * @see {@link https://api.jquery.com/replaceWith/}
  738. */
  739. function replaceWith(content) {
  740. var _this = this;
  741. return (0, utils_js_1.domEach)(this, function (el, i) {
  742. var parent = el.parent;
  743. if (!parent) {
  744. return;
  745. }
  746. var siblings = parent.children;
  747. var cont = typeof content === 'function' ? content.call(el, i, el) : content;
  748. var dom = _this._makeDomArray(cont);
  749. /*
  750. * In the case that `dom` contains nodes that already exist in other
  751. * structures, ensure those nodes are properly removed.
  752. */
  753. (0, parse_js_1.update)(dom, null);
  754. var index = siblings.indexOf(el);
  755. // Completely remove old element
  756. uniqueSplice(siblings, index, 1, dom, parent);
  757. if (!dom.includes(el)) {
  758. el.parent = el.prev = el.next = null;
  759. }
  760. });
  761. }
  762. exports.replaceWith = replaceWith;
  763. /**
  764. * Empties an element, removing all its children.
  765. *
  766. * @category Manipulation
  767. * @example
  768. *
  769. * ```js
  770. * $('ul').empty();
  771. * $.html();
  772. * //=> <ul id="fruits"></ul>
  773. * ```
  774. *
  775. * @returns The instance itself.
  776. * @see {@link https://api.jquery.com/empty/}
  777. */
  778. function empty() {
  779. return (0, utils_js_1.domEach)(this, function (el) {
  780. if (!(0, domhandler_1.hasChildren)(el))
  781. return;
  782. el.children.forEach(function (child) {
  783. child.next = child.prev = child.parent = null;
  784. });
  785. el.children.length = 0;
  786. });
  787. }
  788. exports.empty = empty;
  789. function html(str) {
  790. var _this = this;
  791. if (str === undefined) {
  792. var el = this[0];
  793. if (!el || !(0, domhandler_1.hasChildren)(el))
  794. return null;
  795. return this._render(el.children);
  796. }
  797. return (0, utils_js_1.domEach)(this, function (el) {
  798. if (!(0, domhandler_1.hasChildren)(el))
  799. return;
  800. el.children.forEach(function (child) {
  801. child.next = child.prev = child.parent = null;
  802. });
  803. var content = (0, utils_js_1.isCheerio)(str)
  804. ? str.toArray()
  805. : _this._parse("".concat(str), _this.options, false, el).children;
  806. (0, parse_js_1.update)(content, el);
  807. });
  808. }
  809. exports.html = html;
  810. /**
  811. * Turns the collection to a string. Alias for `.html()`.
  812. *
  813. * @category Manipulation
  814. * @returns The rendered document.
  815. */
  816. function toString() {
  817. return this._render(this);
  818. }
  819. exports.toString = toString;
  820. function text(str) {
  821. var _this = this;
  822. // If `str` is undefined, act as a "getter"
  823. if (str === undefined) {
  824. return (0, static_js_1.text)(this);
  825. }
  826. if (typeof str === 'function') {
  827. // Function support
  828. return (0, utils_js_1.domEach)(this, function (el, i) {
  829. return _this._make(el).text(str.call(el, i, (0, static_js_1.text)([el])));
  830. });
  831. }
  832. // Append text node to each selected elements
  833. return (0, utils_js_1.domEach)(this, function (el) {
  834. if (!(0, domhandler_1.hasChildren)(el))
  835. return;
  836. el.children.forEach(function (child) {
  837. child.next = child.prev = child.parent = null;
  838. });
  839. var textNode = new domhandler_1.Text("".concat(str));
  840. (0, parse_js_1.update)(textNode, el);
  841. });
  842. }
  843. exports.text = text;
  844. /**
  845. * Clone the cheerio object.
  846. *
  847. * @category Manipulation
  848. * @example
  849. *
  850. * ```js
  851. * const moreFruit = $('#fruits').clone();
  852. * ```
  853. *
  854. * @returns The cloned object.
  855. * @see {@link https://api.jquery.com/clone/}
  856. */
  857. function clone() {
  858. return this._make((0, utils_js_1.cloneDom)(this.get()));
  859. }
  860. exports.clone = clone;
  861. //# sourceMappingURL=manipulation.js.map