Comparing version 0.4.2 to 0.5.0
@@ -0,1 +1,9 @@ | ||
0.5.0 / 2012-02-04 | ||
================== | ||
* Transitioned from Coffeescript back to Javascript | ||
* Parser now ignores whitespace | ||
* Fixed issue with double slashes on self-enclosing tags | ||
* Added boolean attributes to html rendering | ||
0.4.2 / 2012-01-16 | ||
@@ -15,8 +23,8 @@ ================== | ||
* Rewrote all unit tests as cheerio transitioned from vows -> mocha | ||
* Internally, renderer.render -> render(...), parser.parse -> parse(...) | ||
* Append, prepend, html, before, after all work with only text (no tags) | ||
* Bugfix: Attributes can now be removed from script and style tags | ||
* Added yield as a single tag | ||
* Cheerio now compatible with node >=0.4.7 | ||
* Rewrote all unit tests as cheerio transitioned from vows -> mocha | ||
* Internally, renderer.render -> render(...), parser.parse -> parse(...) | ||
* Append, prepend, html, before, after all work with only text (no tags) | ||
* Bugfix: Attributes can now be removed from script and style tags | ||
* Added yield as a single tag | ||
* Cheerio now compatible with node >=0.4.7 | ||
@@ -26,3 +34,3 @@ 0.3.2 / 2011-12-1 | ||
* Fixed $(...).text(...) to work with "root" element | ||
* Fixed $(...).text(...) to work with "root" element | ||
@@ -32,6 +40,6 @@ 0.3.1 / 2011-11-25 | ||
* Now relying on cheerio-soupselect instead of node-soupselect | ||
* Removed all lingering htmlparser dependencies | ||
* parser now returns parent "root" element. Root now never needs to be updated when there is multiple roots. This fixes ongoing issues with before(...), after(...) and other manipulation functions | ||
* Added jQuery's $(...).replaceWith(...) | ||
* Now relying on cheerio-soupselect instead of node-soupselect | ||
* Removed all lingering htmlparser dependencies | ||
* parser now returns parent "root" element. Root now never needs to be updated when there is multiple roots. This fixes ongoing issues with before(...), after(...) and other manipulation functions | ||
* Added jQuery's $(...).replaceWith(...) | ||
@@ -41,7 +49,7 @@ 0.3.0 / 2011-11-19 | ||
* Now using htmlparser2 for parsing (2x speed increase, cleaner, actively developed) | ||
* Added benchmark directory for future speed tests | ||
* $("...").dom() was funky, so it was removed in favor of $("...").get(). $.dom() still works the same. | ||
* $.root now correctly static across all instances of $ | ||
* Added a screencast | ||
* Now using htmlparser2 for parsing (2x speed increase, cleaner, actively developed) | ||
* Added benchmark directory for future speed tests | ||
* $("...").dom() was funky, so it was removed in favor of $("...").get(). $.dom() still works the same. | ||
* $.root now correctly static across all instances of $ | ||
* Added a screencast | ||
@@ -51,5 +59,5 @@ 0.2.2 / 2011-11-9 | ||
* Traversing will select `<script>` and `<style>` tags (Closes Issue: #8) | ||
* .text(string) now working with empty elements (Closes Issue: #7) | ||
* Fixed before(...) & after(...) again if there is no parent (Closes Issue: #2) | ||
* Traversing will select `<script>` and `<style>` tags (Closes Issue: #8) | ||
* .text(string) now working with empty elements (Closes Issue: #7) | ||
* Fixed before(...) & after(...) again if there is no parent (Closes Issue: #2) | ||
@@ -59,5 +67,4 @@ 0.2.1 / 2011-11-5 | ||
* Fixed before(...) & after(...) if there is no parent (Closes Issue: #2) | ||
* Comments now rendered correctly (Closes Issue: #5) | ||
* Fixed before(...) & after(...) if there is no parent (Closes Issue: #2) | ||
* Comments now rendered correctly (Closes Issue: #5) | ||
@@ -67,2 +74,2 @@ < 0.2.0 / 2011-10-31 | ||
* Initial release (untracked development) | ||
* Initial release (untracked development) |
31
index.js
@@ -1,19 +0,18 @@ | ||
// Use source if we have coffeescript otherwise use lib | ||
var base; | ||
try { | ||
// Need to have coffeescript installed locally in order to run from src | ||
require('./node_modules/coffee-script'); | ||
base = './src/'; | ||
} catch (e) { | ||
base = './lib/'; | ||
} | ||
exports = module.exports = require('./lib/cheerio'); | ||
exports = module.exports = require(base + 'cheerio'); | ||
/* | ||
Attach objects to cheerio | ||
*/ | ||
exports.parse = require('./lib/parse'); | ||
exports.render = require('./lib/render'); | ||
exports.utils = require('./lib/utils'); | ||
exports.parse = require(base + 'parse'); | ||
exports.render = require(base + 'render'); | ||
exports.utils = require(base + 'utils'); | ||
/* | ||
Export the version | ||
*/ | ||
var version = function() { | ||
var pkg = require('fs').readFileSync(__dirname + '/package.json', 'utf8'); | ||
return JSON.parse(pkg).version; | ||
}; | ||
/* | ||
Attach other modules on here, this will allow testing to be done in mocha without recompiling | ||
*/ | ||
exports.__defineGetter__('version', version); |
@@ -1,102 +0,124 @@ | ||
(function() { | ||
var $, addClass, attr, hasClass, rclass, removeAttr, removeClass, rspace, _; | ||
var _ = require("underscore"), | ||
$ = require("../cheerio"), | ||
rclass = /[\n\t\r]/g, | ||
rspace = /\s+/; | ||
_ = require("underscore"); | ||
var attr = exports.attr = function(name, value) { | ||
return $.access(this, name, value, true, $.attr); | ||
}; | ||
$ = require("../cheerio"); | ||
var removeAttr = exports.removeAttr = function(name) { | ||
this.each(function() { | ||
$.removeAttr(this, name); | ||
}); | ||
return this; | ||
}; | ||
rclass = /[\n\t\r]/g; | ||
var hasClass = exports.hasClass = function(selector) { | ||
var className = " " + selector + " ", | ||
classes, | ||
elem; | ||
rspace = /\s+/; | ||
for(var i = 0; i < this.length; i++) { | ||
elem = this[i]; | ||
// Add spaces to support multiple classes | ||
classes = (" " + elem.attribs["class"] + " ").replace(rclass, " "); | ||
if ($.isTag(elem) && elem.attribs && classes.indexOf(className) > -1) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
attr = exports.attr = function(name, value) { | ||
return $.access(this, name, value, true, $.attr); | ||
}; | ||
var addClass = exports.addClass = function(value) { | ||
// Support functions | ||
if (_.isFunction(value)) { | ||
this.each(function(i) { | ||
var $this = $(this), | ||
className = $this.attr('class') || ""; | ||
removeAttr = exports.removeAttr = function(name) { | ||
return this.each(function() { | ||
return $.removeAttr(this, name); | ||
$this.addClass(value.call(this, i, className)); | ||
}); | ||
}; | ||
} | ||
hasClass = exports.hasClass = function(selector) { | ||
var className, elem, _i, _len; | ||
className = " " + selector + " "; | ||
for (_i = 0, _len = this.length; _i < _len; _i++) { | ||
elem = this[_i]; | ||
if ($.isTag(elem) && elem.attribs && (" " + elem.attribs["class"] + " ").replace(rclass, " ").indexOf(className) > -1) { | ||
return true; | ||
// Return if no value or not a string or function | ||
if (!value || !_.isString(value)) return this; | ||
var classNames = value.split(rspace), | ||
numElements = this.length, | ||
numClasses, | ||
setClass, | ||
$elem; | ||
for(var i = 0; i < numElements; i++) { | ||
$elem = $(this[i]); | ||
// If selected element isnt a tag, move on | ||
if (!$.isTag(this[i])) continue; | ||
// If we don't already have classes | ||
if (!$elem.attr("class")) { | ||
$elem.attr('class', classNames.join(' ').trim()); | ||
} else { | ||
setClass = " " + $elem.attr("class") + " "; | ||
numClasses = classNames.length; | ||
// Check if class already exists | ||
for (var j = 0; j < numClasses; j++) { | ||
if (!~setClass.indexOf(" " + classNames[j] + " ")) | ||
setClass += classNames[j] + " "; | ||
} | ||
$elem.attr('class', setClass.trim()); | ||
} | ||
return false; | ||
}; | ||
} | ||
addClass = exports.addClass = function(value) { | ||
var $elem, className, classNames, elem, setClass, _i, _j, _len, _len2; | ||
if (_.isFunction(value)) { | ||
return this.each(function(i) { | ||
var $this, className; | ||
$this = $(this); | ||
className = $this.attr('class') || ""; | ||
return $this.addClass(value.call(this, i, className)); | ||
}); | ||
return this; | ||
}; | ||
var removeClass = exports.removeClass = function(value) { | ||
// Handle if value is a function | ||
if (_.isFunction(value)) { | ||
this.each(function(j) { | ||
var $this = $(this), | ||
className = $this.attr('class') || ""; | ||
$this.removeClass(value.call(this, j, className)); | ||
}); | ||
} | ||
// If value isnt undefined and also not a string | ||
if(value !== undefined && !_.isString(value)) return this; | ||
var classNames = (value || "").split(rspace), | ||
numClasses = classNames.length, | ||
className, | ||
$elem, | ||
ret; | ||
for (var i = 0, iLen = this.length; i < iLen; i++) { | ||
$elem = $(this[i]); | ||
className = this[i].attribs['class']; | ||
if(!$.isTag(this[i]) || !className) continue; | ||
else if(!value) { | ||
this[i].attribs['class'] = ''; | ||
continue; | ||
} | ||
if (value && _.isString(value)) { | ||
classNames = value.split(rspace); | ||
for (_i = 0, _len = this.length; _i < _len; _i++) { | ||
elem = this[_i]; | ||
$elem = $(elem); | ||
if ($.isTag(elem)) { | ||
if (!$elem.attr("class")) { | ||
$elem.attr('class', classNames.join(' ').trim()); | ||
} else { | ||
setClass = " " + $elem.attr("class") + " "; | ||
for (_j = 0, _len2 = classNames.length; _j < _len2; _j++) { | ||
className = classNames[_j]; | ||
if (!~setClass.indexOf(" " + className + " ")) { | ||
setClass += className + " "; | ||
} | ||
} | ||
$elem.attr('class', setClass.trim()); | ||
} | ||
} | ||
} | ||
} | ||
return this; | ||
}; | ||
removeClass = exports.removeClass = function(value) { | ||
var $elem, className, classNames, elem, ret, _i, _j, _len, _len2; | ||
if (_.isFunction(value)) { | ||
return this.each(function(j) { | ||
var $this, className; | ||
$this = $(this); | ||
className = $this.attr('class') || ""; | ||
return $this.removeClass(value.call(this, j, className)); | ||
}); | ||
// Separate out the classes | ||
ret = (" " + className + " ").replace(rclass, " "); | ||
for (var j = 0; j < numClasses; j++) { | ||
className = classNames[j]; | ||
ret = ret.replace(" " + className + " ", " "); | ||
} | ||
if ((value && _.isString(value)) || value === void 0) { | ||
classNames = (value || "").split(rspace); | ||
for (_i = 0, _len = this.length; _i < _len; _i++) { | ||
elem = this[_i]; | ||
$elem = $(elem); | ||
if ($.isTag(elem) && $elem.attr('class')) { | ||
if (value) { | ||
ret = (" " + $elem.attr('class') + " ").replace(rclass, " "); | ||
for (_j = 0, _len2 = classNames.length; _j < _len2; _j++) { | ||
className = classNames[_j]; | ||
ret = ret.replace(" " + className + " ", " "); | ||
} | ||
$elem.attr('class', ret.trim()); | ||
} else { | ||
$elem.attr('class', ''); | ||
} | ||
} | ||
} | ||
} | ||
return this; | ||
}; | ||
module.exports = $.fn.extend(exports); | ||
this[i].attribs['class'] = ret.trim(); | ||
} | ||
}).call(this); | ||
return this; | ||
}; | ||
module.exports = $.fn.extend(exports); |
@@ -1,64 +0,62 @@ | ||
(function() { | ||
var $, get, pushStack, siblingsAndMe, size, toArray, underscore; | ||
var underscore = require('underscore'), | ||
$ = require('../cheerio'); | ||
var size = exports.size = function() { | ||
return this.length; | ||
}; | ||
underscore = require('underscore'); | ||
var toArray = exports.toArray = function() { | ||
return Array.prototype.slice.call(this, 0); | ||
}; | ||
$ = require('../cheerio'); | ||
var get = exports.get = function(num) { | ||
if (num === undefined) return this.toArray(); | ||
size = exports.size = function() { | ||
return this.length; | ||
}; | ||
if(~num) { | ||
return this[num]; | ||
} else { | ||
// Reverse lookup | ||
return this[this.length + num]; | ||
} | ||
}; | ||
toArray = exports.toArray = function() { | ||
return Array.prototype.slice.call(this, 0); | ||
}; | ||
var pushStack = exports.pushStack = function(elems, name, selector) { | ||
var ret = this.constructor(); | ||
if ($.isArray(elems)) { | ||
push.apply(ret, elems); | ||
} else { | ||
$.merge(ret, elems); | ||
} | ||
ret.prevObject = this; | ||
ret.context = this.context; | ||
if (name === "find") { | ||
ret.selector = this.selector + (this.selector ? " " : "") + selector; | ||
} else if(name) { | ||
ret.selector = this.selector + "." + name + "(" + selector + ")"; | ||
} | ||
return ret; | ||
}; | ||
get = exports.get = function(num) { | ||
if (num === void 0) { | ||
return this.toArray(); | ||
} else { | ||
if (num < 0) { | ||
return this[this.length + num]; | ||
} else { | ||
return this[num]; | ||
} | ||
} | ||
}; | ||
pushStack = exports.pushStack = function(elems, name, selector) { | ||
var ret; | ||
ret = this.constructor(); | ||
if ($.isArray(elems)) { | ||
push.apply(ret, elems); | ||
} else { | ||
$.merge(ret, elems); | ||
} | ||
ret.prevObject = this; | ||
ret.context = this.context; | ||
if (name === "find") { | ||
ret.selector = this.selector + (this.selector ? " " : "") + selector; | ||
} else { | ||
if (name) ret.selector = this.selector + "." + name + "(" + selector + ")"; | ||
} | ||
return ret; | ||
}; | ||
siblingsAndMe = exports.siblingsAndMe = function() { | ||
var element, raw, siblings; | ||
siblings = []; | ||
raw = this[0]; | ||
element = raw; | ||
while (element.prev) { | ||
element = element.prev; | ||
} | ||
var siblingsAndMe = exports.siblingsAndMe = function() { | ||
var siblings = [], | ||
raw = this[0], | ||
element = raw; | ||
while (element.prev) { | ||
element = element.prev; | ||
} | ||
siblings.push(element); | ||
while (element.next) { | ||
element = element.next; | ||
siblings.push(element); | ||
while (element.next) { | ||
element = element.next; | ||
siblings.push(element); | ||
} | ||
return siblings; | ||
}; | ||
} | ||
return siblings; | ||
}; | ||
module.exports = $.fn.extend(exports); | ||
}).call(this); | ||
module.exports = $.fn.extend(exports); |
@@ -1,185 +0,216 @@ | ||
(function() { | ||
var $, after, append, before, empty, html, parse, prepend, remove, removeChild, replaceWith, text, _; | ||
var __slice = Array.prototype.slice; | ||
var _ = require('underscore'), | ||
$ = require('../cheerio'), | ||
parse = require('../parse'), | ||
slice = Array.prototype.slice; | ||
_ = require('underscore'); | ||
var removeChild = function(parent, elem) { | ||
$.each(parent.children, function(i, child) { | ||
if (elem === child) | ||
parent.children.splice(i, 1); | ||
}); | ||
}; | ||
$ = require('../cheerio'); | ||
/* | ||
Creates an array of cheerio objects, | ||
parsing strings if necessary | ||
*/ | ||
var makeCheerioArray = function(elems) { | ||
var dom = [], | ||
len = elems.length, | ||
elem; | ||
parse = require('../parse'); | ||
for(var i = 0; i < len; i++) { | ||
elem = elems[i]; | ||
// If a cheerio object | ||
if(elem.cheerio) { | ||
dom = dom.concat(elem.toArray()); | ||
} else { | ||
dom = dom.concat(parse.eval(elem)); | ||
} | ||
} | ||
removeChild = function(parent, elem) { | ||
return $.each(parent.children, function(i, child) { | ||
if (elem === child) return parent.children.splice(i, 1); | ||
}); | ||
}; | ||
return dom; | ||
}; | ||
append = exports.append = function() { | ||
var dom, elem, elems, _i, _len; | ||
elems = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
dom = []; | ||
for (_i = 0, _len = elems.length; _i < _len; _i++) { | ||
elem = elems[_i]; | ||
if (elem.cheerio) { | ||
dom = dom.concat(elem.toArray()); | ||
} else { | ||
dom = dom.concat(parse.eval(elem)); | ||
} | ||
} | ||
this.each(function() { | ||
if (_.isFunction(elems[0])) {} else { | ||
if (!this.children) this.children = []; | ||
this.children = this.children.concat(dom); | ||
return $.updateDOM(this.children, this); | ||
} | ||
}); | ||
return this; | ||
}; | ||
var append = exports.append = function() { | ||
var elems = slice.call(arguments), | ||
dom = makeCheerioArray(elems); | ||
prepend = exports.prepend = function() { | ||
var dom, elem, elems, _i, _len; | ||
elems = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
dom = []; | ||
for (_i = 0, _len = elems.length; _i < _len; _i++) { | ||
elem = elems[_i]; | ||
if (elem.cheerio) { | ||
dom = dom.concat(elem.toArray()); | ||
} else { | ||
dom = dom.concat(parse.eval(elem)); | ||
} | ||
this.each(function() { | ||
if(_.isFunction(elems[0])) { | ||
// No yet supported | ||
return; | ||
} else { | ||
if(!this.children) this.children = []; | ||
this.children = this.children.concat(dom); | ||
$.updateDOM(this.children, this); | ||
} | ||
this.each(function() { | ||
if (_.isFunction(elems[0])) {} else { | ||
if (!this.children) this.children = []; | ||
this.children = dom.concat(this.children); | ||
return $.updateDOM(this.children, this); | ||
} | ||
}); | ||
return this; | ||
}; | ||
}); | ||
after = exports.after = function() { | ||
var dom, elem, elems, _i, _len; | ||
elems = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
dom = []; | ||
for (_i = 0, _len = elems.length; _i < _len; _i++) { | ||
elem = elems[_i]; | ||
if (elem.cheerio) { | ||
dom = dom.concat(elem.toArray()); | ||
} else { | ||
dom = dom.concat(parse.eval(elem)); | ||
} | ||
} | ||
this.each(function() { | ||
var index, siblings; | ||
siblings = this.parent.children; | ||
index = siblings.indexOf(this); | ||
if (index >= 0) siblings.splice.apply(siblings, [index + 1, 0].concat(dom)); | ||
$.updateDOM(siblings, this.parent); | ||
return this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
return this; | ||
}; | ||
before = exports.before = function() { | ||
var dom, elem, elems, _i, _len; | ||
elems = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
dom = []; | ||
for (_i = 0, _len = elems.length; _i < _len; _i++) { | ||
elem = elems[_i]; | ||
if (elem.cheerio) { | ||
dom = dom.concat(elem.toArray()); | ||
} else { | ||
dom = dom.concat(parse.eval(elem)); | ||
} | ||
/* | ||
TODO: Refactor, only one line difference between, | ||
this function and append | ||
*/ | ||
var prepend = exports.prepend = function() { | ||
var elems = slice.call(arguments), | ||
dom = makeCheerioArray(elems); | ||
this.each(function() { | ||
if(_.isFunction(elems[0])) { | ||
// No yet supported | ||
return; | ||
} else { | ||
if(!this.children) this.children = []; | ||
this.children = dom.concat(this.children); | ||
$.updateDOM(this.children, this); | ||
} | ||
this.each(function() { | ||
var index, siblings; | ||
siblings = this.parent.children; | ||
index = siblings.indexOf(this); | ||
if (index >= 0) siblings.splice.apply(siblings, [index, 0].concat(dom)); | ||
$.updateDOM(siblings, this.parent); | ||
return this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
}); | ||
remove = exports.remove = function(selector) { | ||
var elems; | ||
elems = this; | ||
if (selector) elems = this.find(selector); | ||
elems.each(function() { | ||
var index, siblings; | ||
siblings = this.parent.children; | ||
index = siblings.indexOf(this); | ||
siblings.splice(index, 1); | ||
$.updateDOM(siblings, this.parent); | ||
return this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
return this; | ||
}; | ||
replaceWith = exports.replaceWith = function(content) { | ||
var elems; | ||
elems = parse.eval(content); | ||
return this.each(function() { | ||
var index, siblings; | ||
siblings = this.parent.children; | ||
index = siblings.indexOf(this); | ||
siblings.splice.apply(siblings, [index, 1].concat(elems)); | ||
$.updateDOM(siblings, this.parent); | ||
return this.parent.children = siblings; | ||
}); | ||
}; | ||
var after = exports.after = function() { | ||
var elems = slice.call(arguments), | ||
dom = makeCheerioArray(elems); | ||
empty = exports.empty = function() { | ||
return this.each(function() { | ||
return this.children = []; | ||
this.each(function() { | ||
var siblings = this.parent.children, | ||
index = siblings.indexOf(this); | ||
// If not found, move on | ||
if(!~index) return; | ||
// Add element after `this` element | ||
siblings.splice.apply(siblings, [++index, 0].concat(dom)); | ||
// Update next, prev, and parent pointers | ||
$.updateDOM(siblings, this.parent); | ||
this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
var before = exports.before = function() { | ||
var elems = slice.call(arguments), | ||
dom = makeCheerioArray(elems); | ||
this.each(function() { | ||
var siblings = this.parent.children, | ||
index = siblings.indexOf(this); | ||
// If not found, move on | ||
if(!~index) return; | ||
// Add element before `this` element | ||
siblings.splice.apply(siblings, [index, 0].concat(dom)); | ||
// Update next, prev, and parent pointers | ||
$.updateDOM(siblings, this.parent); | ||
this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
/* | ||
remove([selector]) | ||
*/ | ||
var remove = exports.remove = function(selector) { | ||
var elems = this; | ||
// Filter if we have selector | ||
if(selector) | ||
elems = elems.find(selector); | ||
elems.each(function() { | ||
var siblings = this.parent.children, | ||
index = siblings.indexOf(this); | ||
if(!~index) return; | ||
siblings.splice(index, 1); | ||
// Update next, prev, and parent pointers | ||
$.updateDOM(siblings, this.parent); | ||
this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
var replaceWith = exports.replaceWith = function(content) { | ||
var elems = parse.eval(content); | ||
this.each(function() { | ||
var siblings = this.parent.children, | ||
index = siblings.indexOf(this); | ||
if(!~index) return; | ||
siblings.splice.apply(siblings, [index, 1].concat(elems)); | ||
$.updateDOM(siblings, this.parent); | ||
this.parent.children = siblings; | ||
}); | ||
return this; | ||
}; | ||
var empty = exports.empty = function() { | ||
this.each(function() { | ||
this.children = []; | ||
}); | ||
return this; | ||
}; | ||
var html = exports.html = function(str) { | ||
if(!str || typeof(str) === 'object') | ||
return $.html(this[0]); | ||
str = parse.eval(str); | ||
this.each(function() { | ||
this.children = str; | ||
}); | ||
return this; | ||
}; | ||
var text = exports.text = function(str) { | ||
// If `str` blank or an object | ||
if(!str || typeof(str) === 'object') { | ||
return $.text(this); | ||
} else if (_.isFunction(str)) { | ||
// Function support | ||
this.each(function(i) { | ||
var self = $(this); | ||
return self.text(textString.call(this, i, self.text())); | ||
}); | ||
}; | ||
} | ||
html = exports.html = function(htmlString) { | ||
var htmlElement; | ||
if (typeof htmlString !== "object" && htmlString !== void 0) { | ||
htmlElement = parse.eval(htmlString); | ||
this.each(function(i) { | ||
return this.children = htmlElement; | ||
}); | ||
return this; | ||
} else { | ||
return $.html(this[0]); | ||
} | ||
var elem = { | ||
data : str, | ||
type : 'text', | ||
parent : null, | ||
prev : null, | ||
next : null, | ||
children : [] | ||
}; | ||
text = exports.text = function(textString) { | ||
var textElement; | ||
if (_.isFunction(textString)) { | ||
this.each(function(i) { | ||
var self; | ||
self = $(this); | ||
return self.text(textString.call(this, i, self.text())); | ||
}); | ||
} | ||
if (typeof textString !== "object" && textString !== void 0) { | ||
textElement = { | ||
raw: textString, | ||
data: textString, | ||
type: "text", | ||
parent: null, | ||
prev: null, | ||
next: null, | ||
children: [] | ||
}; | ||
this.each(function(i) { | ||
this.children = textElement; | ||
return $.updateDOM(this.children, this); | ||
}); | ||
return this; | ||
} else { | ||
return $.text(this); | ||
} | ||
}; | ||
// Append text node to each selected elements | ||
this.each(function() { | ||
this.children = elem; | ||
$.updateDOM(this.children, this); | ||
}); | ||
module.exports = $.fn.extend(exports); | ||
return this; | ||
}; | ||
}).call(this); | ||
module.exports = $.fn.extend(exports); |
@@ -1,95 +0,70 @@ | ||
(function() { | ||
var $, children, each, find, next, parent, prev, siblings, soupselect, _; | ||
var _ = require("underscore"), | ||
soupselect = require("cheerio-soupselect"), | ||
$ = require("../cheerio"); | ||
_ = require("underscore"); | ||
var find = exports.find = function(selector) { | ||
if(!selector) return this; | ||
soupselect = require("cheerio-soupselect"); | ||
var elem = soupselect.select(this.toArray(), selector); | ||
return $(elem); | ||
}; | ||
$ = require("../cheerio"); | ||
var parent = exports.parent = function(elem) { | ||
if(this[0] && this[0].parent) | ||
return $(this[0].parent); | ||
else | ||
return null; | ||
}; | ||
/* | ||
Stupidly simple traversal | ||
TODO : Make it more jQuery-like | ||
*/ | ||
var next = exports.next = function(elem) { | ||
if(!this[0]) return null; | ||
find = exports.find = function(selector) { | ||
var elem; | ||
if (!selector) return this; | ||
elem = soupselect.select(this.toArray(), selector); | ||
return $(elem); | ||
}; | ||
var nextSibling = this[0].next; | ||
while(nextSibling) { | ||
if($.isTag(nextSibling)) return $(nextSibling); | ||
nextSibling = nextSibling.next; | ||
} | ||
}; | ||
parent = exports.parent = function(elem) { | ||
if (this[0] && this[0].parent) { | ||
return $(this[0].parent); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
var prev = exports.prev = function(elem) { | ||
if(!this[0]) return null; | ||
next = exports.next = function(elem) { | ||
var nextSibling; | ||
if (!this[0]) return null; | ||
nextSibling = this[0].next; | ||
while (nextSibling) { | ||
if ($.isTag(nextSibling)) return $(nextSibling); | ||
nextSibling = nextSibling.next; | ||
} | ||
return null; | ||
}; | ||
var prevSibling = this[0].prev; | ||
while(prevSibling) { | ||
if($.isTag(prevSibling)) return $(prevSibling); | ||
prevSibling = prevSibling.prev; | ||
} | ||
}; | ||
prev = exports.prev = function(elem) { | ||
var prevSibling; | ||
if (!this[0]) return null; | ||
prevSibling = this[0].prev; | ||
while (prevSibling) { | ||
if ($.isTag(prevSibling)) return $(prevSibling); | ||
prevSibling = prevSibling.prev; | ||
} | ||
return null; | ||
}; | ||
var siblings = exports.siblings = function(elem) { | ||
if(!this[0]) return null; | ||
siblings = exports.siblings = function(elem) { | ||
var sibs; | ||
var _this = this; | ||
if (this.parent()) { | ||
sibs = this.parent().children(); | ||
} else { | ||
sibs = this.siblingsAndMe(); | ||
} | ||
siblings = _.filter(sibs, function(elem) { | ||
return elem !== _this[0] && $.isTag(elem); | ||
}); | ||
return $(siblings); | ||
}; | ||
var self = this, | ||
siblings = (this.parent()) ? this.parent().children() | ||
: this.siblingsAndMe(); | ||
children = exports.children = function(selector) { | ||
if (this[0] && this[0].children) { | ||
children = _.filter(this[0].children, function(elem) { | ||
return $.isTag(elem); | ||
}); | ||
if (selector !== void 0) { | ||
if (_.isNumber(selector)) { | ||
if (children[selector]) { | ||
return $(children[selector]); | ||
} else { | ||
return null; | ||
} | ||
} else { | ||
return $(children).find(selector); | ||
} | ||
} | ||
return $(children); | ||
} else { | ||
return null; | ||
} | ||
}; | ||
siblings = _.filter(siblings, function(elem) { | ||
return (elem !== self[0] && $.isTag(elem)); | ||
}); | ||
each = exports.each = function(callback, args) { | ||
return $.each(this, callback, args); | ||
}; | ||
return $(siblings); | ||
}; | ||
module.exports = $.fn.extend(exports); | ||
var children = exports.children = function(selector) { | ||
if(!this[0] || !this[0].children) return null; | ||
}).call(this); | ||
var children = _.filter(this[0].children, function(elem) { | ||
return ($.isTag(elem)); | ||
}); | ||
if(selector === undefined) return $(children); | ||
else if(_.isNumber(selector)) return $(children[selector]); | ||
return $(children).find(selector); | ||
}; | ||
var each = exports.each = function(callback, args) { | ||
return $.each(this, callback, args); | ||
}; | ||
module.exports = $.fn.extend(exports); |
@@ -1,243 +0,285 @@ | ||
(function() { | ||
var $, access, attr, class2type, dom, each, html, inArray, indexOf, isArray, isTag, load, makeArray, merge, parse, push, rboolean, removeAttr, render, tags, text, toString, type, updateDOM, _; | ||
/* | ||
Module Dependencies | ||
*/ | ||
var _ = require("underscore"), | ||
$ = require("../cheerio"), | ||
parse = require("../parse"), | ||
render = require("../render"), | ||
utils = require('../utils'), | ||
isTag = utils.isTag; | ||
var class2type = {}, | ||
types = 'Boolean Number String Function Array Date Regex Object', | ||
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, | ||
toString = Object.prototype.toString, | ||
push = Array.prototype.push, | ||
indexOf = Array.prototype.indexOf, | ||
tags = { tag : 1, script : 1, style : 1 }; | ||
_ = require("underscore"); | ||
/* | ||
Node Types | ||
directive : 10 | ||
comment : 8 | ||
script : 1 | ||
style : 1 | ||
text : 3 | ||
tag : 1 | ||
*/ | ||
$ = require("../cheerio"); | ||
// Fill in class2type | ||
_.each(types.split(' '), function(name) { | ||
class2type['[object '+ name +']'] = name.toLowerCase(); | ||
}); | ||
parse = require("../parse"); | ||
exports.isTag = isTag; | ||
render = require("../render"); | ||
var updateDOM = exports.updateDOM = function(arr, parent) { | ||
// normalize | ||
arr = $(arr).get(); | ||
// Update neighbors | ||
for(var i = 0; i < arr.length; i++) { | ||
arr[i].prev = arr[i-1] || null; | ||
arr[i].next = arr[i+1] || null; | ||
arr[i].parent = parent || null; | ||
} | ||
// Update parent | ||
parent.children = arr; | ||
return parent; | ||
}; | ||
class2type = {}; | ||
var type = exports.type = function(obj) { | ||
if(obj === null) | ||
return String(obj); | ||
else | ||
return class2type[toString.call(obj)] || 'object'; | ||
}; | ||
_.each("Boolean Number String Function Array Date Regex Object".split(" "), function(name, i) { | ||
return class2type["[object " + name + "]"] = name.toLowerCase(); | ||
}); | ||
var isArray = exports.isArray = function(array) { | ||
return _(this).isArray(); | ||
}; | ||
/* | ||
Node Types | ||
directive : 10 | ||
comment : 8 | ||
script : 1 | ||
style : 1 | ||
text : 3 | ||
tag : 1 | ||
*/ | ||
var merge = exports.merge = function( first, second ) { | ||
var i = first.length, | ||
j = 0; | ||
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i; | ||
if ( typeof second.length === "number" ) { | ||
for ( var l = second.length; j < l; j++ ) { | ||
first[ i++ ] = second[ j ]; | ||
} | ||
toString = Object.prototype.toString; | ||
} else { | ||
while ( second[j] !== undefined ) { | ||
first[ i++ ] = second[ j++ ]; | ||
} | ||
} | ||
push = Array.prototype.push; | ||
first.length = i; | ||
indexOf = Array.prototype.indexOf; | ||
return first; | ||
}; | ||
tags = { | ||
'tag': 1, | ||
'script': 1, | ||
'style': 1 | ||
}; | ||
var makeArray = exports.makeArray = function( array, results ) { | ||
var ret = results || [], | ||
type = $.type(array); | ||
if(!array) return ret; | ||
isTag = exports.isTag = function(type) { | ||
if (type.type) type = type.type; | ||
if (tags[type]) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
if ( array.length == null || type === "string" || type === "function" || type === "regexp") { | ||
push.call( ret, array ); | ||
} else { | ||
merge( ret, array ); | ||
} | ||
return ret; | ||
}; | ||
updateDOM = exports.updateDOM = function(arr, parent) { | ||
var elem, i, _len; | ||
arr = $(arr).get(); | ||
for (i = 0, _len = arr.length; i < _len; i++) { | ||
elem = arr[i]; | ||
arr[i].prev = arr[i - 1] || null; | ||
arr[i].next = arr[i + 1] || null; | ||
arr[i].parent = parent || null; | ||
} | ||
if (!parent.children) parent.children = []; | ||
parent.children = arr; | ||
return parent; | ||
}; | ||
var inArray = exports.inArray = function( elem, array, i ) { | ||
var len; | ||
type = exports.type = function(obj) { | ||
if (obj === null) { | ||
return String(obj); | ||
} else { | ||
return class2type[toString.call(obj)] || "object"; | ||
} | ||
}; | ||
if ( array ) { | ||
if ( indexOf ) { | ||
return indexOf.call( array, elem, i ); | ||
} | ||
isArray = exports.isArray = function(array) { | ||
return _(this).isArray(); | ||
}; | ||
len = array.length; | ||
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; | ||
merge = exports.merge = function(first, second) { | ||
var i, j, l; | ||
i = first.length; | ||
j = 0; | ||
if (typeof second.length === "number") { | ||
l = second.length; | ||
while (j < l) { | ||
first[i++] = second[j]; | ||
j++; | ||
} | ||
} else { | ||
while (second[j] !== void 0) { | ||
first[i++] = second[j++]; | ||
} | ||
} | ||
first.length = i; | ||
return first; | ||
}; | ||
for ( ; i < len; i++ ) { | ||
// Skip accessing in sparse arrays | ||
if ( i in array && array[ i ] === elem ) { | ||
return i; | ||
} | ||
} | ||
} | ||
makeArray = exports.makeArray = function(array, results) { | ||
var ret; | ||
ret = results || []; | ||
if (array) { | ||
type = $.type(array); | ||
if (!(array.length != null) || type === "string" || type === "function" || type === "regexp") { | ||
push.call(ret, array); | ||
} else { | ||
$.merge(ret, array); | ||
} | ||
} | ||
return ret; | ||
}; | ||
return -1; | ||
}; | ||
inArray = exports.inArray = function(elem, array) { | ||
if (!array) return -1; | ||
return indexOf.call(array, elem); | ||
}; | ||
// args is for internal usage only | ||
var each = exports.each = function( object, callback, args ) { | ||
var name, i = 0, | ||
length = object.length, | ||
isObj = length === undefined || _.isFunction( object ); | ||
each = exports.each = function(object, callback, args) { | ||
var i, isObj, length, name; | ||
length = object.length; | ||
i = 0; | ||
isObj = length === void 0 || _.isFunction(object); | ||
if (args) { | ||
if (isObj) { | ||
for (name in object) { | ||
if (callback.apply(object[name], args) === false) break; | ||
} | ||
} else { | ||
while (i < length) { | ||
if (callback.apply(object[i++], args) === false) break; | ||
} | ||
} | ||
} else { | ||
if (isObj) { | ||
for (name in object) { | ||
if (callback.call(object[name], name, object[name]) === false) break; | ||
} | ||
} else { | ||
while (i < length) { | ||
if (callback.call(object[i], i, object[i++]) === false) break; | ||
} | ||
} | ||
} | ||
return object; | ||
}; | ||
if ( args ) { | ||
if ( isObj ) { | ||
for ( name in object ) { | ||
if ( callback.apply( object[ name ], args ) === false ) { | ||
break; | ||
} | ||
} | ||
} else { | ||
for ( ; i < length; ) { | ||
if ( callback.apply( object[ i++ ], args ) === false ) { | ||
break; | ||
} | ||
} | ||
} | ||
access = exports.access = function(elems, key, value, exec, fn, pass) { | ||
var i, k, length; | ||
length = elems.length; | ||
if (typeof key === "object") { | ||
for (k in key) { | ||
access(elems, k, key[k], exec, fn, value); | ||
} | ||
return elems; | ||
} | ||
if (value !== void 0) { | ||
exec = !pass && exec && _.isFunction(value); | ||
i = 0; | ||
while (i < length) { | ||
fn(elems[i], key, (exec ? value.call(elems[i], i, fn(elems[i], key)) : value), pass); | ||
i++; | ||
} | ||
return elems; | ||
} | ||
return (length ? fn(elems[0], key) : void 0); | ||
}; | ||
// A special, fast, case for the most common use of each | ||
} else { | ||
if ( isObj ) { | ||
for ( name in object ) { | ||
if ( callback.call( object[ name ], name, object[ name ] ) === false ) { | ||
break; | ||
} | ||
} | ||
} else { | ||
for ( ; i < length; ) { | ||
if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
attr = exports.attr = function(elem, name, value, pass) { | ||
type = elem.type; | ||
if (!elem || !$.isTag(elem)) return; | ||
if (!elem.attribs) elem.attribs = {}; | ||
if (!name) return elem.attribs; | ||
if (value !== void 0) { | ||
if (value === null) { | ||
return $.removeAttr(elem, name); | ||
} else { | ||
return elem.attribs[name] = "" + value; | ||
} | ||
return object; | ||
}; | ||
// Mutifunctional method to get and set values to a collection | ||
// The value/s can optionally be executed if it's a function | ||
var access = exports.access = function( elems, key, value, exec, fn, pass ) { | ||
var length = elems.length; | ||
// Setting many attributes | ||
if ( typeof key === "object" ) { | ||
for ( var k in key ) { | ||
access( elems, k, key[k], exec, fn, value ); | ||
} | ||
return elems; | ||
} | ||
// Setting one attribute | ||
if ( value !== undefined ) { | ||
// Optionally, function values get executed if exec is true | ||
exec = !pass && exec && _.isFunction(value); | ||
for ( var i = 0; i < length; i++ ) { | ||
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); | ||
} | ||
return elems; | ||
} | ||
// Getting an attribute | ||
return length ? fn( elems[0], key ) : undefined; | ||
}; | ||
var attr = exports.attr = function( elem, name, value, pass ) { | ||
var type = elem.type; | ||
if (!elem || !isTag(elem)) | ||
return undefined; | ||
if (!elem.attribs) { | ||
elem.attribs = {}; | ||
} | ||
// Return the entire attribs object if no attribute specified | ||
if (!name) { | ||
return elem.attribs; | ||
} | ||
if (value !== undefined) { | ||
if (value === null) { | ||
// Remove the attribute | ||
$.removeAttr(elem, name); | ||
} else { | ||
return elem.attribs[name]; | ||
// Set the attribute | ||
elem.attribs[name] = "" + value; | ||
} | ||
}; | ||
} else { | ||
// Get the attributes | ||
return elem.attribs[name]; | ||
} | ||
}; | ||
removeAttr = exports.removeAttr = function(elem, name) { | ||
if (isTag(elem.type) && elem.attribs) { | ||
if (elem.attribs[name]) { | ||
if (rboolean.test(elem.attribs[name])) { | ||
return elem.attribs[name] = false; | ||
} else { | ||
return delete elem.attribs[name]; | ||
} | ||
} | ||
} | ||
}; | ||
var removeAttr = exports.removeAttr = function(elem, name) { | ||
if(!isTag(elem.type) || !elem.attribs || !elem.attribs[name]) | ||
return; | ||
if(rboolean.test(elem.attribs[name])) | ||
elem.attribs[name] = false; | ||
else | ||
delete elem.attribs[name]; | ||
}; | ||
text = exports.text = function(elems) { | ||
var elem, ret, _i, _len; | ||
ret = ""; | ||
if (!elems) return ret; | ||
for (_i = 0, _len = elems.length; _i < _len; _i++) { | ||
elem = elems[_i]; | ||
if (elem.type === "text") { | ||
ret += elem.data; | ||
} else if (elem.children && elem.type !== "comment") { | ||
ret += text(elem.children); | ||
} | ||
} | ||
return ret; | ||
}; | ||
var text = exports.text = function(elems) { | ||
if (!elems) return ''; | ||
load = exports.load = function(html) { | ||
var fn, root; | ||
root = parse(html); | ||
$.extend({ | ||
'root': root | ||
}); | ||
fn = function(selector, context, r) { | ||
if (r) root = parse(r); | ||
return $(selector, context, root); | ||
}; | ||
return _(fn).extend($); | ||
}; | ||
var ret = "", | ||
len = elems.length, | ||
elem; | ||
html = exports.html = function(dom) { | ||
if (dom !== void 0 && dom.type) { | ||
return render(dom); | ||
} else if (this.root && this.root.children) { | ||
return render(this.root.children); | ||
} else { | ||
return ""; | ||
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 += text(elem.children); | ||
} | ||
}; | ||
} | ||
return ret; | ||
}; | ||
dom = exports.dom = function(dom) { | ||
if (dom !== void 0) { | ||
if (dom.type) return dom; | ||
} else if (this.root && this.root.children) { | ||
return this.root.children; | ||
} else { | ||
return ""; | ||
var load = exports.load = function(html) { | ||
var root = parse(html); | ||
function fn(selector, context, r) { | ||
if (r) { | ||
root = parse(r); | ||
} | ||
}; | ||
return $(selector, context, root); | ||
} | ||
$.extend({ | ||
'root': root | ||
}); | ||
return _(fn).extend($); | ||
}; | ||
module.exports = $.extend(exports); | ||
var html = exports.html = function(dom) { | ||
if (dom !== undefined && dom.type) { | ||
return render(dom); | ||
} else if (this.root && this.root.children) { | ||
return render(this.root.children); | ||
} else { | ||
return ""; | ||
} | ||
}; | ||
}).call(this); | ||
var dom = exports.dom = function(dom) { | ||
if (dom && dom.type) { | ||
return dom; | ||
} else if (this.root && this.root.children) { | ||
return this.root.children; | ||
} else { | ||
return ""; | ||
} | ||
}; | ||
module.exports = $.extend(exports); |
@@ -1,86 +0,99 @@ | ||
(function() { | ||
var api, cheerio, parse, path, plugin, soupselect, _, _i, _len; | ||
path = require("path"); | ||
soupselect = require("cheerio-soupselect"); | ||
_ = require("underscore"); | ||
parse = require("./parse"); | ||
cheerio = (function() { | ||
var quickExpr, trimLeft, trimRight; | ||
cheerio = function(selector, context, root) { | ||
return new cheerio.fn.init(selector, context, root); | ||
}; | ||
quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/; | ||
trimLeft = /^\s+/; | ||
trimRight = /\s+$/; | ||
cheerio.fn = cheerio.prototype = { | ||
cheerio: "0.4.2", | ||
constructor: cheerio, | ||
init: function(selector, context, root) { | ||
var elems, match; | ||
if (!selector) return this; | ||
if (root) { | ||
cheerio.extend({ | ||
'root': root | ||
}); | ||
if (_.isString(context)) selector = "" + context + " " + selector; | ||
context = root; | ||
/* | ||
Module dependencies | ||
*/ | ||
var path = require('path'), | ||
soupselect = require('cheerio-soupselect'), | ||
_ = require('underscore'), | ||
parse = require('./parse'); | ||
var cheerio = (function() { | ||
var cheerio = function(selector, context, root) { | ||
return new cheerio.fn.init(selector, context, root); | ||
}; | ||
// A simple way to check for HTML strings or ID strings | ||
// Prioritize #id over <tag> | ||
var quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/; | ||
cheerio.fn = cheerio.prototype = { | ||
cheerio : '[cheerio object]', | ||
constructor : cheerio, | ||
init : function(selector, context, root) { | ||
// Handle $(''), $(null), and $(undefined) | ||
if(!selector) return this; | ||
// Handle the root | ||
if(root) { | ||
cheerio.extend({ 'root' : root }); | ||
if(typeof context === 'string') | ||
selector = context + ' ' + selector; | ||
context = root; | ||
} | ||
// Handle strings | ||
if(typeof selector === 'string') { | ||
var match = null; | ||
// Handle HTML strings | ||
if (selector.charAt(0) === "<" | ||
&& selector.charAt(selector.length - 1) === ">" | ||
&& selector.length >= 3) { | ||
match = [null, selector, null]; | ||
} else { | ||
match = quickExpr.exec(selector); | ||
} | ||
if (typeof selector === "string") { | ||
if (selector.charAt(0) === "<" && selector.charAt(selector.length - 1) === ">" && selector.length >= 3) { | ||
match = [null, selector, null]; | ||
} else { | ||
match = quickExpr.exec(selector); | ||
if (match && (match[1] || !context)) { | ||
if (match[1]) { | ||
// HTML String | ||
root = parse(selector); | ||
return cheerio.merge(this, root.children); | ||
} else if (context) { | ||
// Classes, IDs, just defer to soupselect | ||
var elems = soupselect.select(context, selector); | ||
this.selector = selector; | ||
return cheerio.merge(this, elems); | ||
} | ||
if (match && (match[1] || !context)) { | ||
if (match[1]) { | ||
root = parse(selector); | ||
return cheerio.merge(this, root.children); | ||
} else if (context) { | ||
elems = soupselect.select(context, selector); | ||
this.selector = selector; | ||
return cheerio.merge(this, elems); | ||
} | ||
} | ||
if(!context || context.cheerio) { | ||
// HANDLE : $(expr, $(...)) | ||
return this.constructor(context || root).find(selector); | ||
} | ||
else { | ||
// HANDLE : $(expr, context) | ||
if(typeof context === 'string') { | ||
context = parse(context); | ||
} | ||
/* | ||
Refactor | ||
*/ | ||
if (!context || context.cheerio) { | ||
return this.constructor(context || root).find(selector); | ||
} else { | ||
if (_.isString(context)) context = parse(context); | ||
return this.constructor(context).find(selector); | ||
} | ||
return this.constructor(context).find(selector); | ||
} | ||
return cheerio.makeArray(selector, this); | ||
}, | ||
selector: "", | ||
sort: [].sort, | ||
splice: [].splice, | ||
length: 0 | ||
}; | ||
cheerio.fn.init.prototype = cheerio.fn; | ||
cheerio.extend = cheerio.fn.extend = function(obj) { | ||
return _.extend(this, obj); | ||
}; | ||
return cheerio; | ||
})(); | ||
} | ||
return cheerio.makeArray(selector, this); | ||
}, | ||
selector : '', | ||
sort : [].splice, | ||
length : 0 | ||
}; | ||
cheerio.fn.init.prototype = cheerio.fn; | ||
// Use underscores extend | ||
cheerio.extend = cheerio.fn.extend = function (obj) { | ||
return _.extend(this, obj); | ||
}; | ||
module.exports = cheerio; | ||
return cheerio; | ||
})(); | ||
/* | ||
Plug in the API | ||
*/ | ||
module.exports = cheerio; | ||
api = ['core', 'utils', 'attributes', 'traversing', 'manipulation']; | ||
for (_i = 0, _len = api.length; _i < _len; _i++) { | ||
plugin = api[_i]; | ||
require("./api/" + plugin); | ||
} | ||
}).call(this); | ||
/* | ||
Plug in the API | ||
*/ | ||
var api = 'core utils attributes traversing manipulation'; | ||
api.split(' ').forEach(function(plugin) { | ||
require('./api/' + plugin); | ||
}); |
136
lib/parse.js
@@ -1,72 +0,78 @@ | ||
(function() { | ||
var connect, eval, exports, htmlparser, isTag, parser; | ||
/* | ||
Module Dependencies | ||
*/ | ||
var htmlparser = require('htmlparser2'), | ||
utils = require('./utils'), | ||
isTag = utils.isTag; | ||
htmlparser = require("htmlparser2"); | ||
/* | ||
Parser | ||
*/ | ||
var parser = exports = module.exports = function(content) { | ||
var dom = eval(content), | ||
root = { | ||
type : 'root', | ||
name : 'root', | ||
parent : null, | ||
prev : null, | ||
next : null, | ||
children : [] | ||
}; | ||
root.children = connect(dom, root); | ||
return root; | ||
}; | ||
/* | ||
parser | ||
*/ | ||
var eval = exports.eval = function(content) { | ||
var handler = new htmlparser.DefaultHandler({ | ||
ignoreWhitespace: true | ||
}), | ||
parser = new htmlparser.Parser(handler); | ||
parser.includeLocation = false; | ||
parser.parseComplete(content); | ||
return handler.dom; | ||
}; | ||
parser = exports = module.exports = function(content) { | ||
var dom, root; | ||
dom = eval(content); | ||
root = { | ||
type: 'root', | ||
name: 'root', | ||
parent: null, | ||
prev: null, | ||
next: null, | ||
children: [] | ||
}; | ||
root.children = connect(dom, root); | ||
return root; | ||
}; | ||
var connect = exports.connect = function(dom, parent) { | ||
parent = parent || null; | ||
var prevIndex = -1, | ||
lastElem = null, | ||
len = dom.length; | ||
for(var i = 0; i < len; i++) { | ||
// If tag and no attributes, add empty object | ||
if(isTag(dom[i].type) && dom[i].attribs === undefined) | ||
dom[i].attribs = {}; | ||
// Set parent | ||
dom[i].parent = parent; | ||
// Previous Sibling | ||
dom[i].prev = dom[prevIndex] || null; | ||
// Next sibling | ||
dom[i].next = null; | ||
if(lastElem) lastElem.next = dom[i]; | ||
// Run through the children | ||
if(dom[i].children) | ||
connect(dom[i].children, dom[i]); | ||
else if(isTag(dom[i].type)) | ||
dom[i].children = []; | ||
// Get ready for next element | ||
prevIndex = i; | ||
lastElem = dom[i]; | ||
} | ||
return dom; | ||
}; | ||
eval = exports.eval = function(content) { | ||
var handler; | ||
handler = new htmlparser.DefaultHandler(); | ||
parser = new htmlparser.Parser(handler); | ||
parser.includeLocation = false; | ||
parser.parseComplete(content); | ||
return handler.dom; | ||
}; | ||
module.exports = exports; | ||
isTag = function(type) { | ||
if (type === 'tag' || type === 'script' || type === 'style') { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
connect = exports.connect = function(dom, parent) { | ||
var elem, i, lastElem, prev, prevIndex, _len; | ||
if (parent == null) parent = null; | ||
prevIndex = -1; | ||
lastElem = null; | ||
for (i = 0, _len = dom.length; i < _len; i++) { | ||
elem = dom[i]; | ||
if (isTag(dom[i].type) && dom[i].attribs === void 0) dom[i].attribs = {}; | ||
dom[i].parent = parent; | ||
prev = dom[prevIndex]; | ||
if (prev) { | ||
dom[i].prev = prev; | ||
} else { | ||
dom[i].prev = null; | ||
} | ||
dom[i].next = null; | ||
if (lastElem) lastElem.next = dom[i]; | ||
if (dom[i].children) { | ||
connect(dom[i].children, dom[i]); | ||
} else if (isTag(dom[i].type)) { | ||
dom[i].children = []; | ||
} | ||
prevIndex = i; | ||
lastElem = dom[i]; | ||
} | ||
return dom; | ||
}; | ||
module.exports = exports; | ||
}).call(this); |
@@ -1,87 +0,98 @@ | ||
(function() { | ||
var exports, render, renderComment, renderDirective, renderTag, renderText, singleTag, tagType, utils, _; | ||
/* | ||
Module dependencies | ||
*/ | ||
var _ = require('underscore'), | ||
utils = require('./utils'); | ||
/* | ||
Self-enclosing tags (stolen from node-htmlparser) | ||
*/ | ||
var singleTag = { | ||
area: 1, | ||
base: 1, | ||
basefont: 1, | ||
br: 1, | ||
col: 1, | ||
frame: 1, | ||
hr: 1, | ||
img: 1, | ||
input: 1, | ||
isindex: 1, | ||
link: 1, | ||
meta: 1, | ||
param: 1, | ||
embed: 1, | ||
include: 1, | ||
yield: 1 | ||
}; | ||
_ = require("underscore"); | ||
/* | ||
Tag types from htmlparser | ||
*/ | ||
var tagType = { | ||
tag : 1, | ||
script : 1, | ||
link : 1, | ||
style : 1, | ||
template : 1 | ||
}; | ||
utils = require("./utils"); | ||
var render = exports = module.exports = function(dom, output) { | ||
output = output || []; | ||
if(!_.isArray(dom)) dom = [dom]; | ||
var len = dom.length, | ||
elem; | ||
for(var i = 0; i < len; i++) { | ||
elem = dom[i]; | ||
if(tagType[elem.type]) | ||
output.push(renderTag(elem)); | ||
else if(elem.type === 'directive') | ||
output.push(renderDirective(elem)); | ||
else if(elem.type === 'comment') | ||
output.puhs(renderComment(elem)); | ||
else | ||
output.push(renderText(elem)); | ||
if(elem.children) | ||
output.push(render(elem.children)); | ||
if(!singleTag[elem.name] && tagType[elem.type]) | ||
output.push("</" + elem.name + ">"); | ||
} | ||
return output.join(''); | ||
}; | ||
singleTag = { | ||
area: 1, | ||
base: 1, | ||
basefont: 1, | ||
br: 1, | ||
col: 1, | ||
frame: 1, | ||
hr: 1, | ||
img: 1, | ||
input: 1, | ||
isindex: 1, | ||
link: 1, | ||
meta: 1, | ||
param: 1, | ||
embed: 1, | ||
include: 1, | ||
yield: 1 | ||
}; | ||
var renderTag = exports.renderTag = function(elem) { | ||
var tag = '<' + elem.name; | ||
if(elem.attribs && _.size(elem.attribs)) { | ||
tag += ' ' + utils.formatAttrs(elem.attribs); | ||
} | ||
if(!singleTag[elem.name]) { | ||
tag += '>'; | ||
} else { | ||
tag = tag.trim().replace(/\/$/, ''); | ||
tag += '/>'; | ||
} | ||
tagType = { | ||
tag: 1, | ||
script: 1, | ||
link: 1, | ||
style: 1, | ||
template: 1 | ||
}; | ||
return tag; | ||
}; | ||
render = exports = module.exports = function(dom, output) { | ||
var elem, str, _i, _len; | ||
if (output == null) output = []; | ||
if (!_.isArray(dom)) dom = [dom]; | ||
for (_i = 0, _len = dom.length; _i < _len; _i++) { | ||
elem = dom[_i]; | ||
str = elem.name; | ||
if (tagType[elem.type]) { | ||
output.push(renderTag(elem)); | ||
} else if (elem.type === "directive") { | ||
output.push(renderDirective(elem)); | ||
} else if (elem.type === "comment") { | ||
output.push(renderComment(elem)); | ||
} else { | ||
output.push(renderText(elem)); | ||
} | ||
if (elem.children) output.push(render(elem.children)); | ||
if (!singleTag[elem.name] && tagType[elem.type]) { | ||
output.push("</" + elem.name + ">"); | ||
} | ||
} | ||
return output.join(""); | ||
}; | ||
var renderDirective = exports.renderDirective = function(elem) { | ||
return "<" + elem.data + ">"; | ||
}; | ||
renderTag = exports.renderTag = function(elem) { | ||
var tag; | ||
tag = "<" + elem.name; | ||
if (elem.attribs && _.size(elem.attribs) > 0) { | ||
tag += " " + utils.formatAttributes(elem.attribs); | ||
} | ||
if (!singleTag[elem.name]) { | ||
tag += ">"; | ||
} else { | ||
tag += "/>"; | ||
} | ||
return tag; | ||
}; | ||
var renderText = exports.renderText = function(elem) { | ||
return elem.data; | ||
}; | ||
renderDirective = function(elem) { | ||
return "<" + elem.data + ">"; | ||
}; | ||
var renderComment = exports.renderComment = function(elem) { | ||
return '<!--' + elem.data + '-->'; | ||
}; | ||
renderText = function(elem) { | ||
return elem.data; | ||
}; | ||
renderComment = function(elem) { | ||
return '<!--' + elem.data + '-->'; | ||
}; | ||
module.exports = exports; | ||
}).call(this); | ||
module.exports = exports; |
113
lib/utils.js
@@ -1,72 +0,51 @@ | ||
(function() { | ||
var formatAttributes, print, print_r; | ||
/* | ||
Boolean Attributes | ||
*/ | ||
var booleanAttributes = { | ||
checked: true, | ||
selected: true, | ||
disabled: true, | ||
readonly: true, | ||
multiple: true, | ||
ismap: true, | ||
defer: true, | ||
declare: true, | ||
noresize: true, | ||
nowrap: true, | ||
noshade: true, | ||
compact: true | ||
}; | ||
formatAttributes = exports.formatAttributes = function(attributes) { | ||
var key, output, value; | ||
if (!attributes) return ""; | ||
output = []; | ||
for (key in attributes) { | ||
value = attributes[key]; | ||
if (key === value) { | ||
output.push(key); | ||
} else { | ||
output.push(key + ' = "' + value + '"'); | ||
} | ||
} | ||
return output.join(" "); | ||
}; | ||
/* | ||
Tags | ||
*/ | ||
var tags = { tag : true, script : true, style : true }; | ||
module.exports = exports; | ||
/* | ||
isTag(type) includes <script> and <style> tags | ||
*/ | ||
var isTag = exports.isTag = function(type) { | ||
if(type.type) type = type.type; | ||
return tags[type] || false; | ||
}; | ||
String.prototype.repeat = function(times) { | ||
return new Array(times + 1).join(this); | ||
}; | ||
print = exports.print = function(dom, attr, depth, out) { | ||
var attrs, elem, passback, prop, str, type, val, _i, _j, _len, _len2; | ||
if (attr == null) attr = null; | ||
if (depth == null) depth = 0; | ||
if (out == null) out = []; | ||
for (_i = 0, _len = dom.length; _i < _len; _i++) { | ||
elem = dom[_i]; | ||
type = elem.type; | ||
if (type === "tag" || type === "script" || type === "style") continue; | ||
str = '–'.repeat(depth); | ||
if (depth > 0) { | ||
str += str + " " + elem.name; | ||
} else { | ||
str += elem.name; | ||
} | ||
if (attr) { | ||
attrs = attr.split("."); | ||
val = elem; | ||
passback = true; | ||
for (_j = 0, _len2 = attrs.length; _j < _len2; _j++) { | ||
prop = attrs[_j]; | ||
val = val[prop]; | ||
if (!val) { | ||
passback = false; | ||
break; | ||
} | ||
} | ||
if (passback) str += " ( " + attr + " : " + val + " )"; | ||
} | ||
out.push(str); | ||
if (elem.children) print(elem.children, attr, depth + 1, out); | ||
var formatAttrs = exports.formatAttrs = function(attributes) { | ||
if(!attributes) return ''; | ||
var output = [], | ||
value; | ||
// Loop through the attributes | ||
for (var key in attributes) { | ||
value = attributes[key]; | ||
if (key === value && (booleanAttributes[key] || key === '/')) { | ||
output.push(key); | ||
} else { | ||
output.push(key + ' = "' + value + '"'); | ||
} | ||
return out.join("\n"); | ||
}; | ||
} | ||
return output.join(' '); | ||
}; | ||
print_r = exports.print_r = function(arr, attr) { | ||
var attributes, out; | ||
if (attr == null) attr = "name"; | ||
out = "[ "; | ||
attributes = arr.map(function(elem) { | ||
return elem[attr]; | ||
}); | ||
out += attributes.join(", "); | ||
out += " ]"; | ||
return out; | ||
}; | ||
}).call(this); | ||
module.exports = exports; |
@@ -6,3 +6,3 @@ { | ||
"keywords": ["htmlparser", "jquery", "selector", "scraper"], | ||
"version": "0.4.2", | ||
"version": "0.5.0", | ||
"repository": { | ||
@@ -23,8 +23,5 @@ "type": "git", | ||
"mocha" : "0.x", | ||
"should" : "*" | ||
}, | ||
"scripts": { | ||
"prepublish": "coffee -o lib/ src/", | ||
"test": "coffee -o lib/ src/ && vows tests/test.cheerio.coffee --spec" | ||
"should" : "*", | ||
"coffee-script": "*" | ||
} | ||
} |
@@ -10,3 +10,3 @@ # cheerio | ||
$ = cheerio.load("<h2 class = 'title'>Hello world</h2>"); | ||
$('h2.title').text('Hello there!'); | ||
@@ -28,3 +28,3 @@ $('h2').addClass('welcome'); | ||
__❤ Familiar syntax:__ | ||
Cheerio implements a subset of core jQuery. Cheerio removes all the DOM inconsistencies and browser cruft from the jQuery library, revealing its truly gorgeous API. | ||
Cheerio implements a subset of core jQuery. Cheerio removes all the DOM inconsistencies and browser cruft from the jQuery library, revealing its truly gorgeous API. | ||
@@ -63,6 +63,6 @@ __ϟ Blazingly fast:__ | ||
### Loading | ||
First you need to load in the HTML. This step in jQuery is implicit, since jQuery operates on the one, baked-in DOM. With Cheerio, we need to pass in the HTML document. | ||
First you need to load in the HTML. This step in jQuery is implicit, since jQuery operates on the one, baked-in DOM. With Cheerio, we need to pass in the HTML document. | ||
This is the _preferred_ method: | ||
var cheerio = require('cheerio'), | ||
@@ -85,19 +85,18 @@ $ = cheerio.load('<ul id = "fruits">...</ul>'); | ||
#### $( selector, [context], [root] ) | ||
`selector` searches within the `context` scope which searches within the `root` scope. `selector` and `context` can be an string expression, DOM Element, array of DOM elements, or cheerio object. `root` is typically the HTML document string. | ||
`selector` searches within the `context` scope which searches within the `root` scope. `selector` and `context` can be an string expression, DOM Element, array of DOM elements, or cheerio object. `root` is typically the HTML document string. | ||
This selector method is the starting point for traversing and manipulating the document. Like jQuery, it's the primary method for selecting elements in the document, but unlike jQuery it's built on top of the soup-select library, not the Sizzle engine. | ||
This selector method is the starting point for traversing and manipulating the document. Like jQuery, it's the primary method for selecting elements in the document, but unlike jQuery it's built on top of the soup-select library, not the Sizzle engine. | ||
$(".apple", '#fruits').text() | ||
=> Apple | ||
$('ul .pear').attr('class') | ||
=> pear | ||
$('li[class=orange]').html() | ||
=> <li class = "orange">Orange</li> | ||
> See https://github.com/harryf/node-soupselect for all available selectors | ||
See [cheerio-soupselect]("https://github.com/MatthewMueller/cheerio-soupselect") for a list of all available selectors, | ||
as well as more detailed documentation regarding what is supported and what isn't. | ||
> See http://api.jquery.com/jQuery/ for more information | ||
### Attributes | ||
@@ -107,3 +106,3 @@ Methods for getting and modifying attributes. | ||
#### .attr( name, value ) | ||
Method for getting and setting attributes. Gets the attribute value for only the first element in the matched set. If you set an attribute's value to `null`, you remove that attribute. You may also pass a `map` and `function` like jQuery. | ||
Method for getting and setting attributes. Gets the attribute value for only the first element in the matched set. If you set an attribute's value to `null`, you remove that attribute. You may also pass a `map` and `function` like jQuery. | ||
@@ -135,3 +134,3 @@ $('ul').attr('id') | ||
=> true | ||
#### .addClass( className ) | ||
@@ -156,3 +155,3 @@ Adds class(es) to all of the matched elements. Also accepts a `function` like jQuery. | ||
=> <li class = "">Apple</li> | ||
> See http://api.jquery.com/removeClass/ for more information. | ||
@@ -180,3 +179,3 @@ | ||
=> true | ||
#### .prev() | ||
@@ -193,3 +192,3 @@ Gets the previous sibling thats an element of the first selected element. | ||
=> 2 | ||
#### .children( selector ) | ||
@@ -200,3 +199,3 @@ Gets the children of the first selected element. | ||
=> 3 | ||
$('#fruits').children('.pear').text() | ||
@@ -209,7 +208,7 @@ => Pear | ||
var fruits = []; | ||
$('li').each(function(i, elem) { | ||
fruits[i] = $(this).text(); | ||
}); | ||
fruits.join(', '); | ||
@@ -245,5 +244,5 @@ => Apple, Orange, Pear | ||
</ul> | ||
#### .after( content, [content, ...] ) | ||
Insert content next to each element in the set of matched elements. | ||
Insert content next to each element in the set of matched elements. | ||
@@ -258,5 +257,5 @@ $('.apple').after('<li class = "plum">Plum</li>') | ||
</ul> | ||
#### .before( content, [content, ...] ) | ||
Insert content previous to each element in the set of matched elements. | ||
Insert content previous to each element in the set of matched elements. | ||
@@ -281,3 +280,3 @@ $('.apple').before('<li class = "plum">Plum</li>') | ||
</ul> | ||
#### .empty() | ||
@@ -289,3 +288,3 @@ Empties an element, removing all it's children. | ||
=> <ul id = "fruits"></ul> | ||
#### .html( [htmlString] ) | ||
@@ -296,3 +295,3 @@ Gets an html content string from the first selected element. If `htmlString` is specified, each selected element's content is replaced by the new content. | ||
=> <li class = "orange">Orange</li> | ||
$('#fruits').html('<li class = "mango">Mango</li>').html() | ||
@@ -302,3 +301,3 @@ => <ul id="fruits"> | ||
</ul> | ||
#### .text( [textString] ) | ||
@@ -309,3 +308,3 @@ Get the combined text contents of each element in the set of matched elements, including their descendants.. If `textString` is specified, each selected element's content is replaced by the new text content. | ||
=> Orange | ||
$('ul').text() | ||
@@ -330,3 +329,3 @@ => Apple | ||
=> <li class = "pear">Pear</li> | ||
### Miscellaneous | ||
### Miscellaneous | ||
DOM element methods that don't fit anywhere else | ||
@@ -339,6 +338,6 @@ | ||
=> { raw: 'li class="apple"', ... } | ||
$('li').get() | ||
=> [ {...}, {...}, {...} ] | ||
#### .size() | ||
@@ -349,3 +348,3 @@ Return the number of elements in the cheerio object. Same as `length`. | ||
=> 3 | ||
#### .toArray() | ||
@@ -367,3 +366,3 @@ Retrieve all the DOM elements contained in the jQuery set, as an array. | ||
attribs: { id: 'fruits' }, | ||
children: | ||
children: | ||
[ [Object], | ||
@@ -391,3 +390,3 @@ [Object], | ||
Turns an array-like object (like $) into a native array. | ||
#### $.each( obj, function(index, elem) ) | ||
@@ -408,6 +407,6 @@ Generic iterator function. | ||
To run the test suite, download the repository, then within the cheerio directory, run: | ||
npm install | ||
npm test | ||
npm install . | ||
make test | ||
This will download the development packages and run the test suite. | ||
@@ -420,4 +419,4 @@ ## Special Thanks | ||
This HTML parser can parse anything and produces really consistent results, even when the HTML string has errors. This man is a genius. | ||
__• @harryf's node-soupselect:__ | ||
__• @harryf's node-soupselect:__ | ||
What an incredibly fast and precise CSS selector engine. I never really liked the feature-rich selector engines — I think this engine strikes a great balance. | ||
@@ -430,3 +429,3 @@ | ||
The style, the structure, the open-source"-ness" of this library comes from studying TJ's style and using many of his libraries. This dude consistently pumps out high-quality libraries and has always been more than willing to help or answer questions. You rock TJ. | ||
## License | ||
## License | ||
@@ -454,2 +453,2 @@ (The MIT License) | ||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
2
68524
3
24
875