manipulation.js 26 KB

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