Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

187 linhas
4.5 KiB

há 3 anos
  1. /**
  2. * Module dependencies
  3. */
  4. var serialize = require('dom-serializer'),
  5. select = require('css-select'),
  6. parse = require('./parse'),
  7. _ = {
  8. merge: require('lodash.merge'),
  9. defaults: require('lodash.defaults')
  10. };
  11. /**
  12. * $.load(str)
  13. */
  14. exports.load = function(content, options) {
  15. var Cheerio = require('./cheerio');
  16. options = _.defaults(options || {}, Cheerio.prototype.options);
  17. var root = parse(content, options);
  18. var initialize = function(selector, context, r, opts) {
  19. if (!(this instanceof initialize)) {
  20. return new initialize(selector, context, r, opts);
  21. }
  22. opts = _.defaults(opts || {}, options);
  23. return Cheerio.call(this, selector, context, r || root, opts);
  24. };
  25. // Ensure that selections created by the "loaded" `initialize` function are
  26. // true Cheerio instances.
  27. initialize.prototype = Object.create(Cheerio.prototype);
  28. initialize.prototype.constructor = initialize;
  29. // Mimic jQuery's prototype alias for plugin authors.
  30. initialize.fn = initialize.prototype;
  31. // Keep a reference to the top-level scope so we can chain methods that implicitly
  32. // resolve selectors; e.g. $("<span>").(".bar"), which otherwise loses ._root
  33. initialize.prototype._originalRoot = root;
  34. // Add in the static methods
  35. _.merge(initialize, exports);
  36. // Add in the root
  37. initialize._root = root;
  38. // store options
  39. initialize._options = options;
  40. return initialize;
  41. };
  42. /*
  43. * Helper function
  44. */
  45. function render(that, dom, options) {
  46. if (!dom) {
  47. if (that._root && that._root.children) {
  48. dom = that._root.children;
  49. } else {
  50. return '';
  51. }
  52. } else if (typeof dom === 'string') {
  53. dom = select(dom, that._root, options);
  54. }
  55. return serialize(dom, options);
  56. }
  57. /**
  58. * $.html([selector | dom], [options])
  59. */
  60. exports.html = function(dom, options) {
  61. var Cheerio = require('./cheerio');
  62. // be flexible about parameters, sometimes we call html(),
  63. // with options as only parameter
  64. // check dom argument for dom element specific properties
  65. // assume there is no 'length' or 'type' properties in the options object
  66. if (Object.prototype.toString.call(dom) === '[object Object]' && !options && !('length' in dom) && !('type' in dom))
  67. {
  68. options = dom;
  69. dom = undefined;
  70. }
  71. // sometimes $.html() used without preloading html
  72. // so fallback non existing options to the default ones
  73. options = _.defaults(options || {}, this._options, Cheerio.prototype.options);
  74. return render(this, dom, options);
  75. };
  76. /**
  77. * $.xml([selector | dom])
  78. */
  79. exports.xml = function(dom) {
  80. var options = _.defaults({xmlMode: true}, this._options);
  81. return render(this, dom, options);
  82. };
  83. /**
  84. * $.text(dom)
  85. */
  86. exports.text = function(elems) {
  87. if (!elems) {
  88. elems = this.root();
  89. }
  90. var ret = '',
  91. len = elems.length,
  92. elem;
  93. for (var i = 0; i < len; i++) {
  94. elem = elems[i];
  95. if (elem.type === 'text') ret += elem.data;
  96. else if (elem.children && elem.type !== 'comment') {
  97. ret += exports.text(elem.children);
  98. }
  99. }
  100. return ret;
  101. };
  102. /**
  103. * $.parseHTML(data [, context ] [, keepScripts ])
  104. * Parses a string into an array of DOM nodes. The `context` argument has no
  105. * meaning for Cheerio, but it is maintained for API compatibility with jQuery.
  106. */
  107. exports.parseHTML = function(data, context, keepScripts) {
  108. var parsed;
  109. if (!data || typeof data !== 'string') {
  110. return null;
  111. }
  112. if (typeof context === 'boolean') {
  113. keepScripts = context;
  114. }
  115. parsed = this.load(data);
  116. if (!keepScripts) {
  117. parsed('script').remove();
  118. }
  119. // The `children` array is used by Cheerio internally to group elements that
  120. // share the same parents. When nodes created through `parseHTML` are
  121. // inserted into previously-existing DOM structures, they will be removed
  122. // from the `children` array. The results of `parseHTML` should remain
  123. // constant across these operations, so a shallow copy should be returned.
  124. return parsed.root()[0].children.slice();
  125. };
  126. /**
  127. * $.root()
  128. */
  129. exports.root = function() {
  130. return this(this._root);
  131. };
  132. /**
  133. * $.contains()
  134. */
  135. exports.contains = function(container, contained) {
  136. // According to the jQuery API, an element does not "contain" itself
  137. if (contained === container) {
  138. return false;
  139. }
  140. // Step up the descendants, stopping when the root element is reached
  141. // (signaled by `.parent` returning a reference to the same object)
  142. while (contained && contained !== contained.parent) {
  143. contained = contained.parent;
  144. if (contained === container) {
  145. return true;
  146. }
  147. }
  148. return false;
  149. };