123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /**
- * Module dependencies
- */
- var serialize = require('dom-serializer'),
- select = require('css-select'),
- parse = require('./parse'),
- _ = {
- merge: require('lodash.merge'),
- defaults: require('lodash.defaults')
- };
- /**
- * $.load(str)
- */
- exports.load = function(content, options) {
- var Cheerio = require('./cheerio');
- options = _.defaults(options || {}, Cheerio.prototype.options);
- var root = parse(content, options);
- var initialize = function(selector, context, r, opts) {
- if (!(this instanceof initialize)) {
- return new initialize(selector, context, r, opts);
- }
- opts = _.defaults(opts || {}, options);
- return Cheerio.call(this, selector, context, r || root, opts);
- };
- // Ensure that selections created by the "loaded" `initialize` function are
- // true Cheerio instances.
- initialize.prototype = Object.create(Cheerio.prototype);
- initialize.prototype.constructor = initialize;
- // Mimic jQuery's prototype alias for plugin authors.
- initialize.fn = initialize.prototype;
- // Keep a reference to the top-level scope so we can chain methods that implicitly
- // resolve selectors; e.g. $("<span>").(".bar"), which otherwise loses ._root
- initialize.prototype._originalRoot = root;
- // Add in the static methods
- _.merge(initialize, exports);
- // Add in the root
- initialize._root = root;
- // store options
- initialize._options = options;
- return initialize;
- };
- /*
- * Helper function
- */
- function render(that, dom, options) {
- if (!dom) {
- if (that._root && that._root.children) {
- dom = that._root.children;
- } else {
- return '';
- }
- } else if (typeof dom === 'string') {
- dom = select(dom, that._root, options);
- }
- return serialize(dom, options);
- }
- /**
- * $.html([selector | dom], [options])
- */
- exports.html = function(dom, options) {
- var Cheerio = require('./cheerio');
- // be flexible about parameters, sometimes we call html(),
- // with options as only parameter
- // check dom argument for dom element specific properties
- // assume there is no 'length' or 'type' properties in the options object
- if (Object.prototype.toString.call(dom) === '[object Object]' && !options && !('length' in dom) && !('type' in dom))
- {
- options = dom;
- dom = undefined;
- }
- // sometimes $.html() used without preloading html
- // so fallback non existing options to the default ones
- options = _.defaults(options || {}, this._options, Cheerio.prototype.options);
- return render(this, dom, options);
- };
- /**
- * $.xml([selector | dom])
- */
- exports.xml = function(dom) {
- var options = _.defaults({xmlMode: true}, this._options);
- return render(this, dom, options);
- };
- /**
- * $.text(dom)
- */
- exports.text = function(elems) {
- if (!elems) {
- elems = this.root();
- }
- var ret = '',
- len = elems.length,
- elem;
- for (var i = 0; i < len; i++) {
- elem = elems[i];
- if (elem.type === 'text') ret += elem.data;
- else if (elem.children && elem.type !== 'comment') {
- ret += exports.text(elem.children);
- }
- }
- return ret;
- };
- /**
- * $.parseHTML(data [, context ] [, keepScripts ])
- * Parses a string into an array of DOM nodes. The `context` argument has no
- * meaning for Cheerio, but it is maintained for API compatibility with jQuery.
- */
- exports.parseHTML = function(data, context, keepScripts) {
- var parsed;
- if (!data || typeof data !== 'string') {
- return null;
- }
- if (typeof context === 'boolean') {
- keepScripts = context;
- }
- parsed = this.load(data);
- if (!keepScripts) {
- parsed('script').remove();
- }
- // The `children` array is used by Cheerio internally to group elements that
- // share the same parents. When nodes created through `parseHTML` are
- // inserted into previously-existing DOM structures, they will be removed
- // from the `children` array. The results of `parseHTML` should remain
- // constant across these operations, so a shallow copy should be returned.
- return parsed.root()[0].children.slice();
- };
- /**
- * $.root()
- */
- exports.root = function() {
- return this(this._root);
- };
- /**
- * $.contains()
- */
- exports.contains = function(container, contained) {
- // According to the jQuery API, an element does not "contain" itself
- if (contained === container) {
- return false;
- }
- // Step up the descendants, stopping when the root element is reached
- // (signaled by `.parent` returning a reference to the same object)
- while (contained && contained !== contained.parent) {
- contained = contained.parent;
- if (contained === container) {
- return true;
- }
- }
- return false;
- };
|