1

Deleting checked in node modules

This commit is contained in:
Alex Yatskov 2014-07-11 12:32:26 +09:00
parent d3b78a22c2
commit 9d50644dad
290 changed files with 0 additions and 72257 deletions

View File

@ -1,15 +0,0 @@
{
"indent": 2,
"eqnull": true,
"laxbreak": true,
"proto": true,
"undef": true,
"node": true,
"quotmark": "single",
"globals": {
"expect": true,
"it": true,
"describe": true,
"beforeEach": true
}
}

View File

@ -1,9 +0,0 @@
benchmark/
src/
support/
tests/
examples/
*.sock
*.tmproj
coverage.html
lib-cov

View File

@ -1,6 +0,0 @@
language: node_js
node_js:
- "0.10"
- 0.11
matrix:
fast_finish: true

View File

@ -1,47 +0,0 @@
# Contributing to Cheerio
Thanks for your interest in contributing to the project! Here's a rundown of
how we'd like to work with you:
1. File an issue on GitHub describing the contribution you'd like to make. This
will help us to get you started on the right foot.
2. Create a single commit that addresses the issue:
1. Follow the project's code style (see below)
2. Add enough unit tests to "prove" that your patch is correct
3. Update the project documentation as needed (see below)
4. Describe your approach with as much detail as necessary in the git
commit message
3. Open a pull request, and reference the initial issue in the pull request
message.
# Documentation
Any API change should be reflected in the project's README.md file. Reuse
[jQuery's documentation](http://api.jquery.com) wherever possible, but take
care to note aspects that make Cheerio distinct.
# Code Style
This section is by no means complete. For undocumented stylistic choices,
please try to maintain consistency with the code base.
- Single quotes: `'`
- Whitespace
- Two-space "soft" tabs
- Once space following control flow statements (`if (condition) {` rather
than `if(condition) {`)
- Remove trailing spaces
- [End each file with a newline
character.](https://github.com/editorconfig/editorconfig/wiki/Newline-at-End-of-File-Support)
- Terminate every statement with a semicolon
- Private functionality (for re-using functionality that isn't part of the
jQuery API)
- *Static methods*: If the functionality does not require a reference to a
Cheerio instance, simply define a named function within the module it is
needed.
- *Instance methods*: If the functionality requires a reference to a Cheerio
instance, informally define the method as "private" using the following
conventions:
- Define the method as a function on the Cheerio prototype
- Prefix the method name with an underscore (`_`) character
- Include `@api private` in the code comment the documents the method

View File

@ -1,418 +0,0 @@
0.17.0 / 2014-06-10
==================
0.16.0 / 2014-05-08
==================
* fix `make bench` (David Chambers)
* makefile: add release-* targets (David Chambers)
* alphabetize dependencies (David Chambers)
* Rewrite `data` internals with caching behavior (Mike Pennisi)
* Fence .val example as js (Kevin Sawicki)
* Fixed typos. Deleted trailing whitespace from test/render.js (Nattaphoom Ch)
* Fix manipulation APIs with removed elements (kpdecker)
* Perform manual string parsing for hasClass (kpdecker)
* Fix existing element removal (kpdecker)
* update render tests (Felix Böhm)
* fixed cheerio path (Felix Böhm)
* use `entities.escape` for attribute values (Felix Böhm)
* bump entities version (Felix Böhm)
* remove lowerCaseTags option from readme (Felix Böhm)
* added test case for .html in xmlMode (fb55)
* render xml in `html()` when `xmlMode: true` (fb55)
* use a map for booleanAttributes (fb55)
* update singleTags, use utils.isTag (fb55)
* update travis badge URL (Felix Böhm)
* use typeof instead of _.isString and _.isNumber (fb55)
* use Array.isArray instead of _.isArray (fb55)
* replace _.isFunction with typeof (fb55)
* removed unnecessary error message (fb55)
* decode entities in htmlparser2 (fb55)
* pass options object to CSSselect (fb55)
0.15.0 / 2014-04-08
==================
* Update callbacks to pass element per docs (@kpdecker)
* preserve options (@fb55)
* Use SVG travis badge (@t3chnoboy)
* only use static requires (@fb55)
* Optimize manipulation methods (@kpdecker)
* Optimize add and remove class cases (@kpdecker)
* accept dom of DomHandler to cheerio.load (@nleush)
* added parentsUntil method (@finspin)
* Add performance optimization and bug fix `empty` method (@kpdecker)
0.14.0 / 2014-04-01
==================
* call encodeXML and directly expose decodeHTML (@fb55)
* use latest htmlparser2 and entities versions (@fb55)
* Deprecate `$.fn.toArray` (@jugglinmike)
* Implement `$.fn.get` (@jugglinmike)
* .replaceWith now replaces all selected elements. (@xavi-)
* Correct arguments for 'replaceWith' callback (@jugglinmike)
* switch to lodash (@fb55)
* update to entities@0.5.0 (@fb55)
* Fix attr when $ collection contains text modules (@kpdecker)
* Update to latest version of expect.js (@jugglinmike)
* Remove nodes from their previous structures (@jugglinmike)
* Update render.js (@stevenvachon)
* CDATA test (@stevenvachon)
* only ever one child index for cdata (@stevenvachon)
* don't loop through cdata children array (@stevenvachon)
* proper rendering of CDATA (@stevenvachon)
* Add cheerio-only bench option (@kpdecker)
* Avoid delete operations (@kpdecker)
* Add independent html benchmark (@kpdecker)
* Cache tag check in render (@kpdecker)
* Simplify attribute rendering step (@kpdecker)
* Add html rendering bench case (@kpdecker)
* Remove unnecessary check from removeAttr (@kpdecker)
* Remove unnecessary encoding step for attrs (@kpdecker)
* Add test for removeAttr+attr on boolean attributes (@kpdecker)
* Add single element benchmark case (@kpdecker)
* Optimize filter with selector (@kpdecker)
* Fix passing context as dom node (@alfred-nsh)
* Fix bug in `nextUntil` (@jugglinmike)
* Fix bug in `nextAll` (@jugglinmike)
* Implement `selector` argument of `next` method (@jugglinmike)
* Fix bug in `prevUntil` (@jugglinmike)
* Implement `selector` argument of `prev` method (@jugglinmike)
* Fix bug in `prevAll` (@jugglinmike)
* Fix bug in `siblings` (@jugglinmike)
* Avoid unnecessary indexOf from toggleClass (@kpdecker)
* Use strict equality rather than falsy check in eq (@kpdecker)
* Add benchmark coverage for all $ APIs (@kpdecker)
* Optimize filter Cheerio intermediate creation (@kpdecker)
* Optimize siblings cheerio instance creation (@kpdecker)
* Optimize identity cases for first/last/eq (@kpdecker)
* Use domEach for traversal (@kpdecker)
* Inline children lookup in find (@kpdecker)
* Use domEach in data accessor (@kpdecker)
* Avoid cheerio creation in add/remove/toggleClass (@kpdecker)
* Implement getAttr local helper (@kpdecker)
0.13.1 / 2014-01-07
==================
* Fix select with context in Cheerio function (@jugglinmike)
* Remove unecessary DOM maintenance logic (@jugglinmike)
* Deprecate support for node 0.6
0.13.0 / 2013-12-30
==================
* Remove "root" node (@jugglinmike)
* Fix bug in `prevAll`, `prev`, `nextAll`, `next`, `prevUntil`, `nextUntil` (@jugglinmike)
* Fix `replaceWith` method (@jugglinmike)
* added nextUntil() and prevUntil() (@finspin)
* Remove internal `connect` function (@jugglinmike)
* Rename `Cheerio#make` to document private status (@jugginmike)
* Remove extraneous call to `_.uniq` (@jugglinmike)
* Use CSSselect library directly (@jugglinmike)
* Run CI against Node v0.11 as an allowed failure (@jugginmike)
* Correct bug in `Cheerio#parents` (@jugglinmike)
* Implement `$.fn.end` (@jugginmike)
* Ignore colons inside of url(.*) when parsing css (@Meekohi)
* Introduce rudimentary benchmark suite (@jugglinmike)
* Update HtmlParser2 version (@jugglinmike)
* Correct inconsistency in `$.fn.map` (@jugglinmike)
* fixed traversing tests (@finspin)
* Simplify `make` method (@jugglinmike)
* Avoid shadowing instance methods from arrays (@jugglinmike)
0.12.4 / 2013-11-12
==================
* Coerce JSON values returned by `data` (@jugglinmike)
* issue #284: when rendering HTML, use original data attributes (@Trott)
* Introduce JSHint for automated code linting (@jugglinmike)
* Prevent `find` from returning duplicate elements (@jugglinmike)
* Implement function signature of `replaceWith` (@jugglinmike)
* Implement function signature of `before` (@jugglinmike)
* Implement function signature of `after` (@jugglinmike)
* Implement function signature of `append`/`prepend` (@jugglinmike)
* Extend iteration methods to accept nodes (@jugglinmike)
* Improve `removeClass` (@jugglinmike)
* Complete function signature of `addClass` (@jugglinmike)
* Fix bug in `removeClass` (@jugglinmike)
* Improve contributing.md (@jugglinmike)
* Fix and document .css() (@jugglinmike)
0.12.3 / 2013-10-04
===================
* Add .toggleClass() function (@cyberthom)
* Add contributing guidelines (@jugglinmike)
* Fix bug in `siblings` (@jugglinmike)
* Correct the implementation `filter` and `is` (@jugglinmike)
* add .data() function (@andi-neck)
* add .css() (@yields)
* Implements contents() (@jlep)
0.12.2 / 2013-09-04
==================
* Correct implementation of `$.fn.text` (@jugglinmike)
* Refactor Cheerio array creation (@jugglinmike)
* Extend manipulation methods to accept Arrays (@jugglinmike)
* support .attr(attributeName, function(index, attr)) (@xiaohwan)
0.12.1 / 2013-07-30
==================
* Correct behavior of `Cheerio#parents` (@jugglinmike)
* Double quotes inside attributes kills HTML (@khoomeister)
* Making next({}) and prev({}) return empty object (@absentTelegraph)
* Implement $.parseHTML (@jugglinmike)
* Correct bug in jQuery.fn.closest (@jugglinmike)
* Correct behavior of $.fn.val on 'option' elements (@jugglinmike)
0.12.0 / 2013-06-09
===================
* Breaking Change: Changed context from parent to the actual passed one (@swissmanu)
* Fixed: jquery checkbox val behavior (@jhubble)
* Added: output xml with $.xml() (@Maciek416)
* Bumped: htmlparser2 to 3.1.1
* Fixed: bug in attr(key, val) on empty objects (@farhadi)
* Added: prevAll, nextAll (@lessmind)
* Fixed: Safety check in parents and closest (@zero21xxx)
* Added: .is(sel) (@zero21xxx)
0.11.0 / 2013-04-22
==================
* Added: .closest() (@jeremy-dentel)
* Added: .parents() (@zero21xxx)
* Added: .val() (@rschmukler & @leahciMic)
* Added: Travis support for node 0.10.0 (@jeremy-dentel)
* Fixed: .find() if no selector (@davidchambers)
* Fixed: Propagate syntax errors caused by invalid selectors (@davidchambers)
0.10.8 / 2013-03-11
==================
* Add slice method (SBoudrias)
0.10.7 / 2013-02-10
==================
* Code & doc cleanup (davidchambers)
* Fixed bug in filter (jugglinmike)
0.10.6 / 2013-01-29
==================
* Added `$.contains(...)` (jugglinmike)
* formatting cleanup (davidchambers)
* Bug fix for `.children()` (jugglinmike & davidchambers)
* Remove global `render` bug (wvl)
0.10.5 / 2012-12-18
===================
* Fixed botched publish from 0.10.4 - changes should now be present
0.10.4 / 2012-12-16
==================
* $.find should query descendants only (@jugglinmike)
* Tighter underscore dependency
0.10.3 / 2012-11-18
===================
* fixed outer html bug
* Updated documentation for $(...).html() and $.html()
0.10.2 / 2012-11-17
===================
* Added a toString() method (@bensheldon)
* use `_.each` and `_.map` to simplify cheerio namesakes (@davidchambers)
* Added filter() with tests and updated readme (@bensheldon & @davidchambers)
* Added spaces between attributes rewritten by removeClass (@jos3000)
* updated docs to remove reference to size method (@ironchefpython)
* removed tidy from cheerio
0.10.1 / 2012-10-04
===================
* Fixed regression, filtering with a context (#106)
0.10.0 / 2012-09-24
===================
* Greatly simplified and reorganized the library, reducing the loc by 30%
* Now supports mocha's test-coverage
* Deprecated self-closing tags (HTML5 doesn't require them)
* Fixed error thrown in removeClass(...) @robashton
0.9.2 / 2012-08-10
==================
* added $(...).map(fn)
* manipulation: refactor `makeCheerioArray`
* make .removeClass() remove *all* occurrences (#64)
0.9.1 / 2012-08-03
==================
* fixed bug causing options not to make it to the parser
0.9.0 / 2012-07-24
==================
* Added node 8.x support
* Removed node 4.x support
* Add html(dom) support (@wvl)
* fixed xss vulnerabilities on .attr(), .text(), & .html() (@benatkin, @FB55)
* Rewrote tests into javascript, removing coffeescript dependency (@davidchambers)
* Tons of cleanup (@davidchambers)
0.8.3 / 2012-06-12
==================
* Fixed minor package regression (closes #60)
0.8.2 / 2012-06-11
==================
* Now fails gracefully in cases that involve special chars, which is inline with jQuery (closes #59)
* text() now decode special entities (closes #52)
* updated travis.yml to test node 4.x
0.8.1 / 2012-06-02
==================
* fixed regression where if you created an element, it would update the root
* compatible with node 4.x (again)
0.8.0 / 2012-05-27
==================
* Updated CSS parser to use FB55/CSSselect. Cheerio now supports most CSS3 psuedo selectors thanks to @FB55.
* ignoreWhitespace now on by default again. See #55 for context.
* Changed $(':root') to $.root(), cleaned up $.clone()
* Support for .eq(i) thanks to @alexbardas
* Removed support for node 0.4.x
* Fixed memory leak where package.json was continually loaded
* Tons more tests
0.7.0 / 2012-04-08
==================
* Now testing with node v0.7.7
* Added travis-ci integration
* Replaced should.js with expect.js. Browser testing to come
* Fixed spacing between attributes and their values
* Added HTML pretty print
* Exposed node-htmlparser2 parsing options
* Revert .replaceWith(...) to be consistent with jQuery
0.6.2 / 2012-02-12
==================
* Fixed .replaceWith(...) regression
0.6.1 / 2012-02-12
==================
* Added .first(), .last(), and .clone() commands.
* Option to parse using whitespace added to `.load`.
* Many bug fixes to make cheerio more aligned with jQuery.
* Added $(':root') to select the highest level element.
Many thanks to the contributors that made this release happen: @ironchefpython and @siddMahen
0.6.0 / 2012-02-07
==================
* *Important:* `$(...).html()` now returns inner HTML, which is in line with the jQuery spec
* `$.html()` returns the full HTML string. `$.html([cheerioObject])` will return the outer(selected element's tag) and inner HTML of that object
* Fixed bug that prevented HTML strings with depth (eg. `append('<ul><li><li></ul>')`) from getting `parent`, `next`, `prev` attributes.
* Halted [htmlparser2](https://github.com/FB55/node-htmlparser) at v2.2.2 until single attributes bug gets fixed.
0.5.1 / 2012-02-05
==================
* Fixed minor regression: $(...).text(fn) would fail
0.5.1 / 2012-02-05
==================
* Fixed regression: HTML pages with comments would fail
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
==================
* Multiple selectors support: $('.apple, .orange'). Thanks @siddMahen!
* Update package.json to always use latest cheerio-soupselect
* Fix memory leak in index.js
0.4.1 / 2011-12-19
==================
* Minor packaging changes to allow `make test` to work from npm installation
0.4.0 / 2011-12-19
==================
* 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
0.3.2 / 2011-12-1
=================
* Fixed $(...).text(...) to work with "root" element
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(...)
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
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)
0.2.1 / 2011-11-5
=================
* Fixed before(...) & after(...) if there is no parent (Closes Issue: #2)
* Comments now rendered correctly (Closes Issue: #5)
< 0.2.0 / 2011-10-31
====================
* Initial release (untracked development)

31
scrape/node_modules/cheerio/Makefile generated vendored
View File

@ -1,31 +0,0 @@
REPORTER = dot
XYZ = node_modules/.bin/xyz --message 'Release X.Y.Z' --tag X.Y.Z --script scripts/prepublish
test:
@./node_modules/.bin/jshint lib/ test/
@./node_modules/.bin/mocha --reporter $(REPORTER)
setup:
@npm install
subl:
@subl lib/ test/ package.json index.js
test-cov: lib-cov
@CHEERIO_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
lib-cov:
@jscoverage lib lib-cov
bench:
@./benchmark/benchmark.js
.PHONY: release-major release-minor release-patch
release-major: LEVEL = major
release-minor: LEVEL = minor
release-patch: LEVEL = patch
release-major release-minor release-patch:
@$(XYZ) --increment $(LEVEL)
.PHONY: test build setup subl

793
scrape/node_modules/cheerio/Readme.md generated vendored
View File

@ -1,793 +0,0 @@
# cheerio [![Build Status](https://secure.travis-ci.org/cheeriojs/cheerio.svg?branch=master)](http://travis-ci.org/cheeriojs/cheerio)
Fast, flexible, and lean implementation of core jQuery designed specifically for the server.
## Introduction
Teach your server HTML.
```js
var cheerio = require('cheerio'),
$ = cheerio.load('<h2 class="title">Hello world</h2>');
$('h2.title').text('Hello there!');
$('h2').addClass('welcome');
$.html();
//=> <h2 class="title welcome">Hello there!</h2>
```
## Installation
`npm install cheerio`
## Features
__&#10084; 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.
__&#991; Blazingly fast:__
Cheerio works with a very simple, consistent DOM model. As a result parsing, manipulating, and rendering are incredibly efficient. Preliminary end-to-end benchmarks suggest that cheerio is about __8x__ faster than JSDOM.
__&#10049; Incredibly flexible:__
Cheerio wraps around @FB55's forgiving [htmlparser2](https://github.com/fb55/htmlparser2/). Cheerio can parse nearly any HTML or XML document.
## What about JSDOM?
I wrote cheerio because I found myself increasingly frustrated with JSDOM. For me, there were three main sticking points that I kept running into again and again:
__&#8226; JSDOM's built-in parser is too strict:__
JSDOM's bundled HTML parser cannot handle many popular sites out there today.
__&#8226; JSDOM is too slow:__
Parsing big websites with JSDOM has a noticeable delay.
__&#8226; JSDOM feels too heavy:__
The goal of JSDOM is to provide an identical DOM environment as what we see in the browser. I never really needed all this, I just wanted a simple, familiar way to do HTML manipulation.
## When I would use JSDOM
Cheerio will not solve all your problems. I would still use JSDOM if I needed to work in a browser-like environment on the server, particularly if I wanted to automate functional tests.
## API
### Markup example we'll be using:
```html
<ul id="fruits">
<li class="apple">Apple</li>
<li class="orange">Orange</li>
<li class="pear">Pear</li>
</ul>
```
This is the HTML markup we will be using in all of the API examples.
### 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.
This is the _preferred_ method:
```js
var cheerio = require('cheerio'),
$ = cheerio.load('<ul id="fruits">...</ul>');
```
Optionally, you can also load in the HTML by passing the string as the context:
```js
$ = require('cheerio');
$('ul', '<ul id="fruits">...</ul>');
```
Or as the root:
```js
$ = require('cheerio');
$('li', 'ul', '<ul id="fruits">...</ul>');
```
You can also pass an extra object to `.load()` if you need to modify any
of the default parsing options:
```js
$ = cheerio.load('<ul id="fruits">...</ul>', {
normalizeWhitespace: true,
xmlMode: true
});
```
These parsing options are taken directly from [htmlparser2](https://github.com/fb55/htmlparser2/wiki/Parser-options), therefore any options that can be used in `htmlparser2` are valid in cheerio as well. The default options are:
```js
{
normalizeWhitespace: false,
xmlMode: false,
decodeEntities: true
}
```
For a full list of options and their effects, see [this](https://github.com/fb55/DomHandler) and
[htmlparser2's options](https://github.com/fb55/htmlparser2/wiki/Parser-options).
### Selectors
Cheerio's selector implementation is nearly identical to jQuery's, so the API is very similar.
#### $( 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.
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 CSSSelect library, which implements most of the Sizzle selectors.
```js
$('.apple', '#fruits').text()
//=> Apple
$('ul .pear').attr('class')
//=> pear
$('li[class=orange]').html()
//=> <li class="orange">Orange</li>
```
### Attributes
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.
```js
$('ul').attr('id')
//=> fruits
$('.apple').attr('id', 'favorite').html()
//=> <li class="apple" id="favorite">Apple</li>
```
> See http://api.jquery.com/attr/ for more information
#### .data( name, value )
Method for getting and setting data attributes. Gets or sets the data attribute value for only the first element in the matched set.
```js
$('<div data-apple-color="red"></div>').data()
//=> { appleColor: 'red' }
$('<div data-apple-color="red"></div>').data('data-apple-color')
//=> 'red'
var apple = $('.apple').data('kind', 'mac')
apple.data('kind')
//=> 'mac'
```
> See http://api.jquery.com/data/ for more information
#### .val( [value] )
Method for getting and setting the value of input, select, and textarea. Note: Support for `map`, and `function` has not been added yet.
```js
$('input[type="text"]').val()
//=> input_text
$('input[type="text"]').val('test').html()
//=> <input type="text" value="test"/>
```
#### .removeAttr( name )
Method for removing attributes by `name`.
```js
$('.pear').removeAttr('class').html()
//=> <li>Pear</li>
```
#### .hasClass( className )
Check to see if *any* of the matched elements have the given `className`.
```js
$('.pear').hasClass('pear')
//=> true
$('apple').hasClass('fruit')
//=> false
$('li').hasClass('pear')
//=> true
```
#### .addClass( className )
Adds class(es) to all of the matched elements. Also accepts a `function` like jQuery.
```js
$('.pear').addClass('fruit').html()
//=> <li class="pear fruit">Pear</li>
$('.apple').addClass('fruit red').html()
//=> <li class="apple fruit red">Apple</li>
```
> See http://api.jquery.com/addClass/ for more information.
#### .removeClass( [className] )
Removes one or more space-separated classes from the selected elements. If no `className` is defined, all classes will be removed. Also accepts a `function` like jQuery.
```js
$('.pear').removeClass('pear').html()
//=> <li class="">Pear</li>
$('.apple').addClass('red').removeClass().html()
//=> <li class="">Apple</li>
```
> See http://api.jquery.com/removeClass/ for more information.
#### .toggleClass( className, [switch] )
Add or remove class(es) from the matched elements, depending on either the class's presence or the value of the switch argument. Also accepts a `function` like jQuery.
```js
$('.apple.green').toggleClass('fruit green red').html()
//=> <li class="apple fruit red">Apple</li>
$('.apple.green').toggleClass('fruit green red', true).html()
//=> <li class="apple green fruit red">Apple</li>
```
> See http://api.jquery.com/toggleClass/ for more information.
#### .is( selector )
#### .is( element )
#### .is( selection )
#### .is( function(index) )
Checks the current list of elements and returns `true` if _any_ of the elements match the selector. If using an element or Cheerio selection, returns `true` if _any_ of the elements match. If using a predicate function, the function is executed in the context of the selected element, so `this` refers to the current element.
### Traversing
#### .find(selector)
Get a set of descendants filtered by `selector` of each element in the current set of matched elements.
```js
$('#fruits').find('li').length
//=> 3
```
#### .parent([selector])
Get the parent of each element in the current set of matched elements, optionally filtered by a selector.
```js
$('.pear').parent().attr('id')
//=> fruits
```
#### .parents([selector])
Get a set of parents filtered by `selector` of each element in the current set of match elements.
```js
$('.orange').parents().length
// => 2
$('.orange').parents('#fruits').length
// => 1
```
#### .parentsUntil([selector][,filter])
Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or cheerio object.
```js
$('.orange').parentsUntil('#food').length
// => 1
```
#### .closest(selector)
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
```js
$('.orange').closest()
// => []
$('.orange').closest('.apple')
// => []
$('.orange').closest('li')
// => [<li class="orange">Orange</li>]
$('.orange').closest('#fruits')
// => [<ul id="fruits"> ... </ul>]
```
#### .next([selector])
Gets the next sibling of the first selected element, optionally filtered by a selector.
```js
$('.apple').next().hasClass('orange')
//=> true
```
#### .nextAll()
Gets all the following siblings of the first selected element.
```js
$('.apple').nextAll()
//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
```
#### .nextUntil()
Gets all the following siblings up to but not including the element matched by the selector.
```js
$('.apple').nextUntil('.pear')
//=> [<li class="orange">Orange</li>]
```
#### .prev([selector])
Gets the previous sibling of the first selected element optionally filtered by a selector.
```js
$('.orange').prev().hasClass('apple')
//=> true
```
#### .prevAll()
Gets all the preceding siblings of the first selected element.
```js
$('.pear').prevAll()
//=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
```
#### .prevUntil()
Gets all the preceding siblings up to but not including the element matched by the selector.
```js
$('.pear').prevUntil('.apple')
//=> [<li class="orange">Orange</li>]
```
#### .slice( start, [end] )
Gets the elements matching the specified range
```js
$('li').slice(1).eq(0).text()
//=> 'Orange'
$('li').slice(1, 2).length
//=> 1
```
#### .siblings( selector )
Gets the first selected element's siblings, excluding itself.
```js
$('.pear').siblings().length
//=> 2
$('.pear').siblings('.orange').length
//=> 1
```
#### .children( selector )
Gets the children of the first selected element.
```js
$('#fruits').children().length
//=> 3
$('#fruits').children('.pear').text()
//=> Pear
```
#### .contents()
Gets the children of each element in the set of matched elements, including text and comment nodes.
```js
$('#fruits').contents().length
//=> 3
```
#### .each( function(index, element) )
Iterates over a cheerio object, executing a function for each matched element. When the callback is fired, the function is fired in the context of the DOM element, so `this` refers to the current element, which is equivalent to the function parameter `element`. To break out of the `each` loop early, return with `false`.
```js
var fruits = [];
$('li').each(function(i, elem) {
fruits[i] = $(this).text();
});
fruits.join(', ');
//=> Apple, Orange, Pear
```
#### .map( function(index, element) )
Pass each element in the current matched set through a function, producing a new Cheerio object containing the return values. The function can return an individual data item or an array of data items to be inserted into the resulting set. If an array is returned, the elements inside the array are inserted into the set. If the function returns null or undefined, no element will be inserted.
```js
$('li').map(function(i, el) {
// this === el
return $('<div>').text($(this).text());
}).html();
//=> <div>apple</div><div>orange</div><div>pear</div>
```
#### .filter( selector ) <br /> .filter( selection ) <br /> .filter( element ) <br /> .filter( function(index) )
Iterates over a cheerio object, reducing the set of selector elements to those that match the selector or pass the function's test. When a Cheerio selection is specified, return only the elements contained in that selection. When an element is specified, return only that element (if it is contained in the original selection). If using the function method, the function is executed in the context of the selected element, so `this` refers to the current element.
Selector:
```js
$('li').filter('.orange').attr('class');
//=> orange
```
Function:
```js
$('li').filter(function(i, el) {
// this === el
return $(this).attr('class') === 'orange';
}).attr('class')
//=> orange
```
#### .first()
Will select the first element of a cheerio object
```js
$('#fruits').children().first().text()
//=> Apple
```
#### .last()
Will select the last element of a cheerio object
```js
$('#fruits').children().last().text()
//=> Pear
```
#### .eq( i )
Reduce the set of matched elements to the one at the specified index. Use `.eq(-i)` to count backwards from the last selected element.
```js
$('li').eq(0).text()
//=> Apple
$('li').eq(-1).text()
//=> Pear
```
#### .get( [i] )
Retrieve the DOM elements matched by the Cheerio object. If an index is specified, retrieve one of the elements matched by the Cheerio object:
```js
$('li').get(0).name
//=> li
```
If no index is specified, retrieve all elements matched by the Cheerio object:
```js
$('li').get().length
//=> 3
```
#### .end()
End the most recent filtering operation in the current chain and return the set of matched elements to its previous state.
```js
$('li').eq(0).end().length
//=> 3
```
#### .add( selector [, context] )
#### .add( element )
#### .add( elements )
#### .add( html )
#### .add( selection )
Add elements to the set of matched elements.
```js
$('.apple').add('.orange').length
//=> 2
```
### Manipulation
Methods for modifying the DOM structure.
#### .append( content, [content, ...] )
Inserts content as the *last* child of each of the selected elements.
```js
$('ul').append('<li class="plum">Plum</li>')
$.html()
//=> <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// <li class="plum">Plum</li>
// </ul>
```
#### .prepend( content, [content, ...] )
Inserts content as the *first* child of each of the selected elements.
```js
$('ul').prepend('<li class="plum">Plum</li>')
$.html()
//=> <ul id="fruits">
// <li class="plum">Plum</li>
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// </ul>
```
#### .after( content, [content, ...] )
Insert content next to each element in the set of matched elements.
```js
$('.apple').after('<li class="plum">Plum</li>')
$.html()
//=> <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="plum">Plum</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// </ul>
```
#### .before( content, [content, ...] )
Insert content previous to each element in the set of matched elements.
```js
$('.apple').before('<li class="plum">Plum</li>')
$.html()
//=> <ul id="fruits">
// <li class="plum">Plum</li>
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// </ul>
```
#### .remove( [selector] )
Removes the set of matched elements from the DOM and all their children. `selector` filters the set of matched elements to be removed.
```js
$('.pear').remove()
$.html()
//=> <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// </ul>
```
#### .replaceWith( content )
Replaces matched elements with `content`.
```js
var plum = $('<li class="plum">Plum</li>')
$('.pear').replaceWith(plum)
$.html()
//=> <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="plum">Plum</li>
// </ul>
```
#### .empty()
Empties an element, removing all it's children.
```js
$('ul').empty()
$.html()
//=> <ul id="fruits"></ul>
```
#### .html( [htmlString] )
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.
```js
$('.orange').html()
//=> Orange
$('#fruits').html('<li class="mango">Mango</li>').html()
//=> <li class="mango">Mango</li>
```
#### .text( [textString] )
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.
```js
$('.orange').text()
//=> Orange
$('ul').text()
//=> Apple
// Orange
// Pear
```
#### .css( [propertName] ) <br /> .css( [ propertyNames] ) <br /> .css( [propertyName], [value] ) <br /> .css( [propertName], [function] ) <br /> .css( [properties] )
Get the value of a style property for the first element in the set of matched elements or set one or more CSS properties for every matched element.
### Rendering
When you're ready to render the document, you can use the `html` utility function:
```js
$.html()
//=> <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// </ul>
```
If you want to return the outerHTML you can use `$.html(selector)`:
```js
$.html('.pear')
//=> <li class="pear">Pear</li>
```
By default, `html` will leave some tags open. Sometimes you may instead want to render a valid XML document. For example, you might parse the following XML snippet:
```xml
$ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');
```
... and later want to render to XML. To do this, you can use the 'xml' utility function:
```js
$.xml()
//=> <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>
```
### Miscellaneous
DOM element methods that don't fit anywhere else
#### .clone() ####
Clone the cheerio object.
```js
var moreFruit = $('#fruits').clone()
```
### Utilities
#### $.root
Sometimes you need to work with the top-level root element. To query it, you can use `$.root()`.
```js
$.root().append('<ul id="vegetables"></ul>').html();
//=> <ul id="fruits">...</ul><ul id="vegetables"></ul>
```
#### $.contains( container, contained )
Checks to see if the `contained` DOM element is a descendent of the `container` DOM element.
#### $.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 compatability.
## Screencasts
http://vimeo.com/31950192
> This video tutorial is a follow-up to Nettut's "How to Scrape Web Pages with Node.js and jQuery", using cheerio instead of JSDOM + jQuery. This video shows how easy it is to use cheerio and how much faster cheerio is than JSDOM + jQuery.
## Test Coverage
Cheerio has high-test coverage, you can view the report [here](https://s3.amazonaws.com/MattMueller/Coverage/cheerio.html).
## Testing
To run the test suite, download the repository, then within the cheerio directory, run:
```shell
make setup
make test
```
This will download the development packages and run the test suite.
## Contributors
These are some of the contributors that have made cheerio possible:
```
project : cheerio
repo age : 2 years, 6 months
active : 285 days
commits : 762
files : 36
authors :
293 Matt Mueller 38.5%
133 Matthew Mueller 17.5%
92 Mike Pennisi 12.1%
54 David Chambers 7.1%
30 kpdecker 3.9%
19 Felix Böhm 2.5%
17 fb55 2.2%
15 Siddharth Mahendraker 2.0%
11 Adam Bretz 1.4%
8 Nazar Leush 1.0%
7 ironchefpython 0.9%
6 Jarno Leppänen 0.8%
5 Ben Sheldon 0.7%
5 Jos Shepherd 0.7%
5 Ryan Schmukler 0.7%
5 Steven Vachon 0.7%
4 Maciej Adwent 0.5%
4 Amir Abu Shareb 0.5%
3 jeremy.dentel@brandingbrand.com 0.4%
3 Andi Neck 0.4%
2 steve 0.3%
2 alexbardas 0.3%
2 finspin 0.3%
2 Ali Farhadi 0.3%
2 Chris Khoo 0.3%
2 Rob Ashton 0.3%
2 Thomas Heymann 0.3%
2 Jaro Spisak 0.3%
2 Dan Dascalescu 0.3%
2 Torstein Thune 0.3%
2 Wayne Larsen 0.3%
1 Timm Preetz 0.1%
1 Xavi 0.1%
1 Alex Shaindlin 0.1%
1 mattym 0.1%
1 Felix Böhm 0.1%
1 Farid Neshat 0.1%
1 Dmitry Mazuro 0.1%
1 Jeremy Hubble 0.1%
1 nevermind 0.1%
1 Manuel Alabor 0.1%
1 Matt Liegey 0.1%
1 Chris O'Hara 0.1%
1 Michael Holroyd 0.1%
1 Michiel De Mey 0.1%
1 Ben Atkin 0.1%
1 Rich Trott 0.1%
1 Rob "Hurricane" Ashton 0.1%
1 Robin Gloster 0.1%
1 Simon Boudrias 0.1%
1 Sindre Sorhus 0.1%
1 xiaohwan 0.1%
```
## Special Thanks
This library stands on the shoulders of some incredible developers. A special thanks to:
__&#8226; @FB55 for node-htmlparser2 & CSSSelect:__
Felix has a knack for writing speedy parsing engines. He completely re-wrote both @tautologistic's `node-htmlparser` and @harry's `node-soupselect` from the ground up, making both of them much faster and more flexible. Cheerio would not be possible without his foundational work
__&#8226; @jQuery team for jQuery:__
The core API is the best of its class and despite dealing with all the browser inconsistencies the code base is extremely clean and easy to follow. Much of cheerio's implementation and documentation is from jQuery. Thanks guys.
__&#8226; @visionmedia:__
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
(The MIT License)
Copyright (c) 2012 Matt Mueller &lt;mattmuelle@gmail.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

11
scrape/node_modules/cheerio/index.js generated vendored
View File

@ -1,11 +0,0 @@
/**
* Export cheerio (with )
*/
exports = module.exports = require('./lib/cheerio');
/*
Export the version
*/
exports.version = require('./package').version;

View File

@ -1,413 +0,0 @@
var _ = require('lodash'),
utils = require('../utils'),
isTag = utils.isTag,
domEach = utils.domEach,
hasOwn = Object.prototype.hasOwnProperty,
camelCase = utils.camelCase,
cssCase = utils.cssCase,
rspace = /\s+/,
dataAttrPrefix = 'data-',
// Lookup table for coercing string data-* attributes to their corresponding
// JavaScript primitives
primitives = {
null: null,
true: true,
false: false
},
// Attributes that are booleans
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
// Matches strings that look like JSON objects or arrays
rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;
var getAttr = function(elem, name) {
if (!elem || !isTag(elem)) return;
if (!elem.attribs) {
elem.attribs = {};
}
// Return the entire attribs object if no attribute specified
if (!name) {
return elem.attribs;
}
if (hasOwn.call(elem.attribs, name)) {
// Get the (decoded) attribute
return elem.attribs[name];
}
};
var setAttr = function(el, name, value) {
if (value === null) {
removeAttribute(el, name);
} else {
el.attribs[name] = value+'';
}
};
var attr = exports.attr = function(name, value) {
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
if (typeof value === 'function') {
return domEach(this, function(i, el) {
setAttr(el, name, value.call(el, i, el.attribs[name]));
});
}
return domEach(this, function(i, el) {
if (!isTag(el)) return;
if (typeof name === 'object') {
_.each(name, function(name, key) {
el.attribs[key] = name+'';
});
} else {
setAttr(el, name, value);
}
});
}
return getAttr(this[0], name);
};
var setData = function(el, name, value) {
if (typeof name === 'object') return _.extend(el.data, name);
if (typeof name === 'string' && value !== undefined) {
el.data[name] = value;
} else if (typeof name === 'object') {
_.exend(el.data, name);
}
};
// Read the specified attribute from the equivalent HTML5 `data-*` attribute,
// and (if present) cache the value in the node's internal data store. If no
// attribute name is specified, read *all* HTML5 `data-*` attributes in this
// manner.
var readData = function(el, name) {
var readAll = arguments.length === 1;
var domNames, domName, jsNames, jsName, value, idx, length;
if (readAll) {
domNames = Object.keys(el.attribs).filter(function(attrName) {
return attrName.slice(0, dataAttrPrefix.length) === dataAttrPrefix;
});
jsNames = domNames.map(function(domName) {
return camelCase(domName.slice(dataAttrPrefix.length));
});
} else {
domNames = [dataAttrPrefix + cssCase(name)];
jsNames = [name];
}
for (idx = 0, length = domNames.length; idx < length; ++idx) {
domName = domNames[idx];
jsName = jsNames[idx];
if (hasOwn.call(el.attribs, domName)) {
value = el.attribs[domName];
if (hasOwn.call(primitives, value)) {
value = primitives[value];
} else if (value === String(Number(value))) {
value = Number(value);
} else if (rbrace.test(value)) {
value = JSON.parse(value);
}
el.data[jsName] = value;
}
}
return readAll ? el.data : value;
};
var data = exports.data = function(name, value) {
var elem = this[0];
if (!elem || !isTag(elem)) return;
if (!elem.data) {
elem.data = {};
}
// Return the entire data object if no data specified
if (!name) {
return readData(elem);
}
// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
domEach(this, function(i, el) {
setData(el, name, value);
});
return this;
} else if (hasOwn.call(elem.data, name)) {
return elem.data[name];
}
return readData(elem, name);
};
/**
* Get the value of an element
*/
var val = exports.val = function(value) {
var querying = arguments.length === 0,
element = this[0];
if(!element) return;
switch (element.name) {
case 'textarea':
return this.text(value);
case 'input':
switch (this.attr('type')) {
case 'radio':
var queryString = 'input[type=radio][name=' + this.attr('name') + ']:checked';
var parentEl, root;
// Go up until we hit a form or root
parentEl = this.closest('form');
if (parentEl.length === 0) {
root = (this.parents().last()[0] || this[0]).root;
parentEl = this._make(root);
}
if (querying) {
return parentEl.find(queryString).attr('value');
} else {
parentEl.find(':checked').removeAttr('checked');
parentEl.find('input[type=radio][value="' + value + '"]').attr('checked', '');
return this;
}
break;
default:
return this.attr('value', value);
}
return;
case 'select':
var option = this.find('option:selected'),
returnValue;
if (option === undefined) return undefined;
if (!querying) {
if (!this.attr().hasOwnProperty('multiple') && typeof value == 'object') {
return this;
}
if (typeof value != 'object') {
value = [value];
}
this.find('option').removeAttr('selected');
for (var i = 0; i < value.length; i++) {
this.find('option[value="' + value[i] + '"]').attr('selected', '');
}
return this;
}
returnValue = option.attr('value');
if (this.attr().hasOwnProperty('multiple')) {
returnValue = [];
domEach(option, function(i, el) {
returnValue.push(el.attribs.value);
});
}
return returnValue;
case 'option':
if (!querying) {
this.attr('value', value);
return this;
}
return this.attr('value');
}
};
/**
* Remove an attribute
*/
var removeAttribute = function(elem, name) {
if (!elem.attribs || !hasOwn.call(elem.attribs, name))
return;
if (name === elem.attribs[name] && rboolean.test(elem.attribs[name]))
elem.attribs[name] = false;
else
delete elem.attribs[name];
};
var removeAttr = exports.removeAttr = function(name) {
domEach(this, function(i, elem) {
removeAttribute(elem, name);
});
return this;
};
var hasClass = exports.hasClass = function(className) {
return _.any(this, function(elem) {
var attrs = elem.attribs,
clazz = attrs && attrs['class'],
idx = -1,
end;
if (clazz) {
while ((idx = clazz.indexOf(className, idx+1)) > -1) {
end = idx + className.length;
if ((idx === 0 || rspace.test(clazz[idx-1]))
&& (end === clazz.length || rspace.test(clazz[end]))) {
return true;
}
}
}
});
};
var addClass = exports.addClass = function(value) {
// Support functions
if (typeof value === 'function') {
return domEach(this, function(i, el) {
var className = el.attribs['class'] || '';
addClass.call([el], value.call(el, i, className));
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string') return this;
var classNames = value.split(rspace),
numElements = this.length;
for (var i = 0; i < numElements; i++) {
// If selected element isn't a tag, move on
if (!isTag(this[i])) continue;
// If we don't already have classes
var className = getAttr(this[i], 'class'),
numClasses,
setClass;
if (!className) {
setAttr(this[i], 'class', classNames.join(' ').trim());
} else {
setClass = ' ' + className + ' ';
numClasses = classNames.length;
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
var appendClass = classNames[j] + ' ';
if (!~setClass.indexOf(' ' + appendClass))
setClass += appendClass;
}
setAttr(this[i], 'class', setClass.trim());
}
}
return this;
};
var splitClass = function(className) {
return className ? className.trim().split(rspace) : [];
};
var removeClass = exports.removeClass = function(value) {
var classes,
numClasses,
removeAll;
// Handle if value is a function
if (typeof value === 'function') {
return domEach(this, function(i, el) {
removeClass.call([el], value.call(el, i, el.attribs['class'] || ''));
});
}
classes = splitClass(value);
numClasses = classes.length;
removeAll = arguments.length === 0;
return domEach(this, function(i, el) {
if (!isTag(el)) return;
if (removeAll) {
// Short circuit the remove all case as this is the nice one
el.attribs.class = '';
} else {
var elClasses = splitClass(el.attribs.class),
index,
changed;
for (var j = 0; j < numClasses; j++) {
index = elClasses.indexOf(classes[j]);
if (index >= 0) {
elClasses.splice(index, 1);
changed = true;
// We have to do another pass to ensure that there are not duplicate
// classes listed
j--;
}
}
if (changed) {
el.attribs.class = elClasses.join(' ');
}
}
});
};
var toggleClass = exports.toggleClass = function(value, stateVal) {
// Support functions
if (typeof value === 'function') {
return domEach(this, function(i, el) {
toggleClass.call([el], value.call(el, i, el.attribs['class'] || '', stateVal), stateVal);
});
}
// Return if no value or not a string or function
if (!value || typeof value !== 'string') return this;
var classNames = value.split(rspace),
numClasses = classNames.length,
state = typeof stateVal === 'boolean' ? stateVal ? 1 : -1 : 0,
numElements = this.length,
elementClasses,
index;
for (var i = 0; i < numElements; i++) {
// If selected element isn't a tag, move on
if (!isTag(this[i])) continue;
elementClasses = splitClass(this[i].attribs.class);
// Check if class already exists
for (var j = 0; j < numClasses; j++) {
// Check if the class name is currently defined
index = elementClasses.indexOf(classNames[j]);
// Add if stateValue === true or we are toggling and there is no value
if (state >= 0 && index < 0) {
elementClasses.push(classNames[j]);
} else if (state <= 0 && index >= 0) {
// Otherwise remove but only if the item exists
elementClasses.splice(index, 1);
}
}
this[i].attribs.class = elementClasses.join(' ');
}
return this;
};
var is = exports.is = function (selector) {
if (selector) {
return this.filter(selector).length > 0;
}
return false;
};

View File

@ -1,118 +0,0 @@
var _ = require('lodash'),
domEach = require('../utils').domEach;
var toString = Object.prototype.toString;
/**
* Set / Get css.
*
* @param {String|Object} prop
* @param {String} val
* @return {self}
* @api public
*/
exports.css = function(prop, val) {
if (arguments.length === 2 ||
// When `prop` is a "plain" object
(toString.call(prop) === '[object Object]')) {
return domEach(this, function(idx, el) {
setCss(el, prop, val, idx);
});
} else {
return getCss(this[0], prop);
}
};
/**
* Set styles of all elements.
*
* @param {String|Object} prop
* @param {String} val
* @param {Number} idx - optional index within the selection
* @return {self}
* @api private
*/
function setCss(el, prop, val, idx) {
if ('string' == typeof prop) {
var styles = getCss(el);
if (typeof val === 'function') {
val = val.call(el, idx, el);
}
if (val === '') {
delete styles[prop];
} else if (val != null) {
styles[prop] = val;
}
el.attribs.style = stringify(styles);
} else if ('object' == typeof prop) {
Object.keys(prop).forEach(function(k){
setCss(el, k, prop[k]);
});
}
}
/**
* Get parsed styles of the first element.
*
* @param {String} prop
* @return {Object}
* @api private
*/
function getCss(el, prop) {
var styles = parse(el.attribs.style);
if (typeof prop === 'string') {
return styles[prop];
} else if (Array.isArray(prop)) {
return _.pick(styles, prop);
} else {
return styles;
}
}
/**
* Stringify `obj` to styles.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function stringify(obj) {
return Object.keys(obj || {})
.reduce(function(str, prop){
return str += ''
+ (str ? ' ' : '')
+ prop
+ ': '
+ obj[prop]
+ ';';
}, '');
}
/**
* Parse `styles`.
*
* @param {String} styles
* @return {Object}
* @api private
*/
function parse(styles) {
styles = (styles || '').trim();
if (!styles) return {};
return styles
.split(';')
.reduce(function(obj, str){
var n = str.indexOf(':');
// skip if there is no :, or if it is the first/last character
if (n < 1 || n === str.length-1) return obj;
obj[str.slice(0,n).trim()] = str.slice(n+1).trim();
return obj;
}, {});
}

View File

@ -1,304 +0,0 @@
var _ = require('lodash'),
parse = require('../parse'),
$ = require('../static'),
updateDOM = parse.update,
evaluate = parse.evaluate,
utils = require('../utils'),
domEach = utils.domEach,
encode = utils.encode,
slice = Array.prototype.slice;
// Create an array of nodes, recursing into arrays and parsing strings if
// necessary
exports._makeDomArray = function makeDomArray(elem) {
if (elem == null) {
return [];
} else if (elem.cheerio) {
return elem.get();
} else if (Array.isArray(elem)) {
return _.flatten(elem.map(makeDomArray, this));
} else if (typeof elem === 'string') {
return evaluate(elem, this.options);
} else {
return [elem];
}
};
var _insert = function(concatenator) {
return function() {
var self = this,
elems = slice.call(arguments),
dom = this._makeDomArray(elems);
if (typeof elems[0] === 'function') {
return domEach(this, function(i, el) {
dom = self._makeDomArray(elems[0].call(el, i, $.html(el.children)));
concatenator(dom, el.children, el);
});
} else {
return domEach(this, function(i, el) {
concatenator(dom, el.children, el);
});
}
};
};
/*
* Modify an array in-place, removing some number of elements and adding new
* elements directly following them.
*
* @param {Array} array Target array to splice.
* @param {Number} spliceIdx Index at which to begin changing the array.
* @param {Number} spliceCount Number of elements to remove from the array.
* @param {Array} newElems Elements to insert into the array.
*
* @api private
*/
var uniqueSplice = function(array, spliceIdx, spliceCount, newElems, parent) {
var spliceArgs = [spliceIdx, spliceCount].concat(newElems),
prev = array[spliceIdx - 1] || null,
next = array[spliceIdx] || null;
var idx, len, prevIdx, node, oldParent;
// Before splicing in new elements, ensure they do not already appear in the
// current array.
for (idx = 0, len = newElems.length; idx < len; ++idx) {
node = newElems[idx];
oldParent = node.parent || node.root;
prevIdx = oldParent && oldParent.children.indexOf(newElems[idx]);
if (oldParent && prevIdx > -1) {
oldParent.children.splice(prevIdx, 1);
if (parent === oldParent && spliceIdx > prevIdx) {
spliceArgs[0]--;
}
}
node.root = null;
node.parent = parent;
if (node.prev) {
node.prev.next = node.next || null;
}
if (node.next) {
node.next.prev = node.prev || null;
}
node.prev = newElems[idx - 1] || prev;
node.next = newElems[idx + 1] || next;
}
if (prev) {
prev.next = newElems[0];
}
if (next) {
next.prev = newElems[newElems.length - 1];
}
return array.splice.apply(array, spliceArgs);
};
var append = exports.append = _insert(function(dom, children, parent) {
uniqueSplice(children, children.length, 0, dom, parent);
});
var prepend = exports.prepend = _insert(function(dom, children, parent) {
uniqueSplice(children, 0, 0, dom, parent);
});
var after = exports.after = function() {
var elems = slice.call(arguments),
dom = this._makeDomArray(elems),
self = this;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
// If not found, move on
if (!~index) return;
if (typeof elems[0] === 'function') {
dom = self._makeDomArray(elems[0].call(el, i));
}
// Add element after `this` element
uniqueSplice(siblings, ++index, 0, dom, parent);
});
return this;
};
var before = exports.before = function() {
var elems = slice.call(arguments),
dom = this._makeDomArray(elems),
self = this;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
// If not found, move on
if (!~index) return;
if (typeof elems[0] === 'function') {
dom = self._makeDomArray(elems[0].call(el, i));
}
// Add element before `el` element
uniqueSplice(siblings, index, 0, dom, parent);
});
return this;
};
/*
remove([selector])
*/
var remove = exports.remove = function(selector) {
var elems = this;
// Filter if we have selector
if (selector)
elems = elems.filter(selector);
domEach(elems, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
index = siblings.indexOf(el);
if (!~index) return;
siblings.splice(index, 1);
if (el.prev) {
el.prev.next = el.next;
}
if (el.next) {
el.next.prev = el.prev;
}
el.prev = el.next = el.parent = el.root = null;
});
return this;
};
var replaceWith = exports.replaceWith = function(content) {
var self = this;
domEach(this, function(i, el) {
var parent = el.parent || el.root;
if (!parent) {
return;
}
var siblings = parent.children,
dom = self._makeDomArray(typeof content === 'function' ? content.call(el, i, el) : content),
index;
// In the case that `dom` contains nodes that already exist in other
// structures, ensure those nodes are properly removed.
updateDOM(dom, null);
index = siblings.indexOf(el);
// Completely remove old element
uniqueSplice(siblings, index, 1, dom, parent);
el.parent = el.prev = el.next = el.root = null;
});
return this;
};
var empty = exports.empty = function() {
domEach(this, function(i, el) {
_.each(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
el.children.length = 0;
});
return this;
};
/**
* Set/Get the HTML
*/
var html = exports.html = function(str) {
if (str === undefined) {
if (!this[0] || !this[0].children) return null;
return $.html(this[0].children, this.options);
}
var opts = this.options;
domEach(this, function(i, el) {
_.each(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
var content = str.cheerio ? str.clone().get() : evaluate(str, opts);
updateDOM(content, el);
});
return this;
};
var toString = exports.toString = function() {
return $.html(this);
};
var text = exports.text = function(str) {
// If `str` is undefined, act as a "getter"
if (str === undefined) {
return $.text(this);
} else if (typeof str === 'function') {
// Function support
return domEach(this, function(i, el) {
var $el = [el];
return text.call($el, str.call(el, i, $.text($el)));
});
}
// Append text node to each selected elements
domEach(this, function(i, el) {
_.each(el.children, function(el) {
el.next = el.prev = el.parent = null;
});
var elem = {
data: str,
type: 'text',
parent: el,
prev: null,
next: null,
children: []
};
updateDOM(elem, el);
});
return this;
};
var clone = exports.clone = function() {
// Turn it into HTML, then recreate it,
// Seems to be the easiest way to reconnect everything correctly
return this._make($.html(this));
};

View File

@ -1,361 +0,0 @@
var _ = require('lodash'),
select = require('CSSselect'),
utils = require('../utils'),
domEach = utils.domEach,
uniqueSort = require('htmlparser2').DomUtils.uniqueSort,
isTag = utils.isTag;
var find = exports.find = function(selector) {
var elems = _.reduce(this, function(memo, elem) {
return memo.concat(_.filter(elem.children, isTag));
}, []);
return this._make(select(selector, elems, this.options));
};
// Get the parent of each element in the current set of matched elements,
// optionally filtered by a selector.
var parent = exports.parent = function(selector) {
var set = [];
var $set;
domEach(this, function(idx, elem) {
var parentElem = elem.parent;
if (parentElem && set.indexOf(parentElem) < 0) {
set.push(parentElem);
}
});
if (arguments.length) {
set = filter.call(set, selector, this);
}
return this._make(set);
};
var parents = exports.parents = function(selector) {
var parentNodes = [];
// When multiple DOM elements are in the original set, the resulting set will
// be in *reverse* order of the original elements as well, with duplicates
// removed.
this.get().reverse().forEach(function(elem) {
traverseParents(this, elem.parent, selector, Infinity)
.forEach(function(node) {
if (parentNodes.indexOf(node) === -1) {
parentNodes.push(node);
}
}
);
}, this);
return this._make(parentNodes);
};
var parentsUntil = exports.parentsUntil = function(selector, filter) {
var parentNodes = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.parents().toArray(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.toArray();
} else if (selector) {
untilNode = selector;
}
// When multiple DOM elements are in the original set, the resulting set will
// be in *reverse* order of the original elements as well, with duplicates
// removed.
this.toArray().reverse().forEach(function(elem) {
while ((elem = elem.parent)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && parentNodes.indexOf(elem) === -1) { parentNodes.push(elem); }
} else {
break;
}
}
}, this);
return this._make(filter ? select(filter, parentNodes, this.options) : parentNodes);
};
// For each element in the set, get the first element that matches the selector
// by testing the element itself and traversing up through its ancestors in the
// DOM tree.
var closest = exports.closest = function(selector) {
var set = [];
if (!selector) {
return this._make(set);
}
domEach(this, function(idx, elem) {
var closestElem = traverseParents(this, elem, selector, 1)[0];
// Do not add duplicate elements to the set
if (closestElem && set.indexOf(closestElem) < 0) {
set.push(closestElem);
}
}.bind(this));
return this._make(set);
};
var next = exports.next = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if (isTag(elem)) {
elems.push(elem);
return;
}
}
});
return selector ? filter.call(elems, selector, this) : this._make(elems);
};
var nextAll = exports.nextAll = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
}
});
return selector ? filter.call(elems, selector, this) : this._make(elems);
};
var nextUntil = exports.nextUntil = function(selector, filterSelector) {
if (!this[0]) { return this; }
var elems = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.nextAll().get(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.get();
} else if (selector) {
untilNode = selector;
}
_.forEach(this, function(elem) {
while ((elem = elem.next)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
} else {
break;
}
}
});
return filterSelector ?
filter.call(elems, filterSelector, this) :
this._make(elems);
};
var prev = exports.prev = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if (isTag(elem)) {
elems.push(elem);
return;
}
}
});
return selector ? filter.call(elems, selector, this) : this._make(elems);
};
var prevAll = exports.prevAll = function(selector) {
if (!this[0]) { return this; }
var elems = [];
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
}
});
return selector ? filter.call(elems, selector, this) : this._make(elems);
};
var prevUntil = exports.prevUntil = function(selector, filterSelector) {
if (!this[0]) { return this; }
var elems = [], untilNode, untilNodes;
if (typeof selector === 'string') {
untilNode = select(selector, this.prevAll().get(), this.options)[0];
} else if (selector && selector.cheerio) {
untilNodes = selector.get();
} else if (selector) {
untilNode = selector;
}
_.forEach(this, function(elem) {
while ((elem = elem.prev)) {
if ((untilNode && elem !== untilNode) ||
(untilNodes && untilNodes.indexOf(elem) === -1) ||
(!untilNode && !untilNodes)) {
if (isTag(elem) && elems.indexOf(elem) === -1) {
elems.push(elem);
}
} else {
break;
}
}
});
return filterSelector ?
filter.call(elems, filterSelector, this) :
this._make(elems);
};
var siblings = exports.siblings = function(selector) {
var parent = this.parent();
var elems = _.filter(
parent ? parent.children() : this.siblingsAndMe(),
function(elem) { return isTag(elem) && !this.is(elem); },
this
);
if (selector !== undefined) {
return filter.call(elems, selector, this);
} else {
return this._make(elems);
}
};
var children = exports.children = function(selector) {
var elems = _.reduce(this, function(memo, elem) {
return memo.concat(_.filter(elem.children, isTag));
}, []);
if (selector === undefined) return this._make(elems);
else if (typeof selector === 'number') return this._make(elems[selector]);
return filter.call(elems, selector, this);
};
var contents = exports.contents = function() {
return this._make(_.reduce(this, function(all, elem) {
all.push.apply(all, elem.children);
return all;
}, []));
};
var each = exports.each = function(fn) {
var i = 0, len = this.length;
while (i < len && fn.call(this[i], i, this[i]) !== false) ++i;
return this;
};
var map = exports.map = function(fn) {
return this._make(_.reduce(this, function(memo, el, i) {
var val = fn.call(el, i, el);
return val == null ? memo : memo.concat(val);
}, []));
};
var filter = exports.filter = function(match, container) {
container = container || this;
var make = _.bind(container._make, container);
var filterFn;
if (typeof match === 'string') {
filterFn = select.compile(match, container.options);
} else if (typeof match === 'function') {
filterFn = function(el, i) {
return match.call(el, i, el);
};
} else if (match.cheerio) {
filterFn = match.is.bind(match);
} else {
filterFn = function(el) {
return match === el;
};
}
return make(_.filter(this, filterFn));
};
var first = exports.first = function() {
return this.length > 1 ? this._make(this[0]) : this;
};
var last = exports.last = function() {
return this.length > 1 ? this._make(this[this.length - 1]) : this;
};
// Reduce the set of matched elements to the one at the specified index.
var eq = exports.eq = function(i) {
i = +i;
// Use the first identity optimization if possible
if (i === 0 && this.length <= 1) return this;
if (i < 0) i = this.length + i;
return this[i] ? this._make(this[i]) : this._make([]);
};
// Retrieve the DOM elements matched by the jQuery object.
var get = exports.get = function(i) {
if (i == null) {
return Array.prototype.slice.call(this);
} else {
return this[i < 0 ? (this.length + i) : i];
}
};
var slice = exports.slice = function() {
return this._make([].slice.apply(this, arguments));
};
function traverseParents(self, elem, selector, limit) {
var elems = [];
while (elem && elems.length < limit) {
if (!selector || filter.call([elem], selector, self).length) {
elems.push(elem);
}
elem = elem.parent;
}
return elems;
}
// End the most recent filtering operation in the current chain and return the
// set of matched elements to its previous state.
var end = exports.end = function() {
return this.prevObject || this._make([]);
};
var add = exports.add = function(other, context) {
var selection = this._make(other, context);
var contents = uniqueSort(selection.get().concat(this.get()));
for (var i = 0; i < contents.length; ++i) {
selection[i] = contents[i];
}
selection.length = contents.length;
return selection;
};

View File

@ -1,161 +0,0 @@
/*
Module dependencies
*/
var path = require('path'),
parse = require('./parse'),
_ = require('lodash');
/*
* The API
*/
var api = [
require('./api/attributes'),
require('./api/traversing'),
require('./api/manipulation'),
require('./api/css')
];
/*
* A simple way to check for HTML strings or ID strings
*/
var quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;
/*
* Instance of cheerio
*/
var Cheerio = module.exports = function(selector, context, root, options) {
if (!(this instanceof Cheerio)) return new Cheerio(selector, context, root, options);
this.options = _.defaults(options || {}, this.options);
// $(), $(null), $(undefined), $(false)
if (!selector) return this;
if (root) {
if (typeof root === 'string') root = parse(root, this.options);
this._root = Cheerio.call(this, root);
}
// $($)
if (selector.cheerio) return selector;
// $(dom)
if (isNode(selector))
selector = [selector];
// $([dom])
if (Array.isArray(selector)) {
_.forEach(selector, function(elem, idx) {
this[idx] = elem;
}, this);
this.length = selector.length;
return this;
}
// $(<html>)
if (typeof selector === 'string' && isHtml(selector)) {
return Cheerio.call(this, parse(selector, this.options).children);
}
// If we don't have a context, maybe we have a root, from loading
if (!context) {
context = this._root;
} else if (typeof context === 'string') {
if (isHtml(context)) {
// $('li', '<ul>...</ul>')
context = parse(context, this.options);
context = Cheerio.call(this, context);
} else {
// $('li', 'ul')
selector = [context, selector].join(' ');
context = this._root;
}
// $('li', node), $('li', [nodes])
} else if (!context.cheerio) {
context = Cheerio.call(this, context);
}
// If we still don't have a context, return
if (!context) return this;
// #id, .class, tag
return context.find(selector);
};
/**
* Mix in `static`
*/
_.extend(Cheerio, require('./static'));
/*
* Set a signature of the object
*/
Cheerio.prototype.cheerio = '[cheerio object]';
/*
* Cheerio default options
*/
Cheerio.prototype.options = {
normalizeWhitespace: false,
xmlMode: false,
decodeEntities: true
};
/*
* Make cheerio an array-like object
*/
Cheerio.prototype.length = 0;
Cheerio.prototype.splice = Array.prototype.splice;
/*
* Check if string is HTML
*/
var isHtml = function(str) {
// Faster than running regex, if str starts with `<` and ends with `>`, assume it's HTML
if (str.charAt(0) === '<' && str.charAt(str.length - 1) === '>' && str.length >= 3) return true;
// Run the regex
var match = quickExpr.exec(str);
return !!(match && match[1]);
};
/*
* Make a cheerio object
*
* @api private
*/
Cheerio.prototype._make = function(dom, context) {
var cheerio = new Cheerio(dom, context, this._root, this.options);
cheerio.prevObject = this;
return cheerio;
};
/**
* Turn a cheerio object into an array
*
* @deprecated
*/
Cheerio.prototype.toArray = function() {
return this.get();
};
/**
* Plug in the API
*/
api.forEach(function(mod) {
_.extend(Cheerio.prototype, mod);
});
var isNode = function(obj) {
return obj.name || obj.type === 'text' || obj.type === 'comment';
};

View File

@ -1,93 +0,0 @@
/*
Module Dependencies
*/
var htmlparser = require('htmlparser2'),
utils = require('./utils');
/*
Parser
*/
exports = module.exports = function(content, options) {
var dom = evaluate(content, options);
// Generic root element
var root = {
type: 'root',
name: 'root',
parent: null,
prev: null,
next: null,
children: []
};
// Update the dom using the root
update(dom, root);
return root;
};
var evaluate = exports.evaluate = function(content, options) {
// options = options || $.fn.options;
var dom;
if (typeof content === 'string' || Buffer.isBuffer(content)) {
dom = htmlparser.parseDOM(content, options);
} else {
dom = content;
}
return dom;
};
/*
Update the dom structure, for one changed layer
*/
var update = exports.update = function(arr, parent) {
// normalize
if (!Array.isArray(arr)) arr = [arr];
// Update parent
if (parent) {
parent.children = arr;
} else {
parent = null;
}
// Update neighbors
for (var i = 0; i < arr.length; i++) {
var node = arr[i];
// Cleanly remove existing nodes from their previous structures.
var oldParent = node.parent || node.root,
oldSiblings = oldParent && oldParent.children;
if (oldSiblings && oldSiblings !== arr) {
oldSiblings.splice(oldSiblings.indexOf(node), 1);
if (node.prev) {
node.prev.next = node.next;
}
if (node.next) {
node.next.prev = node.prev;
}
}
if (parent) {
node.prev = arr[i - 1] || null;
node.next = arr[i + 1] || null;
} else {
node.prev = node.next = null;
}
if (parent && parent.type === 'root') {
node.root = parent;
node.parent = null;
} else {
node.root = null;
node.parent = parent;
}
}
return parent;
};
// module.exports = $.extend(exports);

View File

@ -1,156 +0,0 @@
/**
* Module dependencies
*/
var select = require('CSSselect'),
parse = require('./parse'),
render = require('dom-serializer'),
_ = require('lodash');
/**
* $.load(str)
*/
var load = 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) {
opts = _.defaults(opts || {}, options);
return new Cheerio(selector, context, r || root, opts);
};
// Add in the static methods
initialize.__proto__ = exports;
// Add in the root
initialize._root = root;
// store options
initialize._options = options;
return initialize;
};
/**
* $.html([selector | dom])
*/
var html = 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);
if (dom) {
dom = (typeof dom === 'string') ? select(dom, this._root, options) : dom;
return render(dom, options);
} else if (this._root && this._root.children) {
return render(this._root.children, options);
} else {
return '';
}
};
/**
* $.xml([selector | dom])
*/
var xml = exports.xml = function(dom) {
if (dom) {
dom = (typeof dom === 'string') ? select(dom, this._root, this.options) : dom;
return render(dom, { xmlMode: true });
} else if (this._root && this._root.children) {
return render(this._root.children, { xmlMode: true });
} else {
return '';
}
};
/**
* $.text(dom)
*/
var text = exports.text = function(elems) {
if (!elems) return '';
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 += 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.
*/
var parseHTML = 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();
}
return parsed.root()[0].children;
};
/**
* $.root()
*/
var root = exports.root = function() {
return this(this._root);
};
/**
* $.contains()
*/
var 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;
};

View File

@ -1,51 +0,0 @@
/**
* HTML Tags
*/
var tags = { tag: true, script: true, style: true };
/**
* Check if the DOM element is a tag
*
* isTag(type) includes <script> and <style> tags
*/
exports.isTag = function(type) {
if (type.type) type = type.type;
return tags[type] || false;
};
/**
* Convert a string to camel case notation.
* @param {String} str String to be converted.
* @return {String} String in camel case notation.
*/
exports.camelCase = function(str) {
return str.replace(/[_.-](\w|$)/g, function(_, x) {
return x.toUpperCase();
});
};
/**
* Convert a string from camel case to "CSS case", where word boundaries are
* described by hyphens ("-") and all characters are lower-case.
* @param {String} str String to be converted.
* @return {string} String in "CSS case".
*/
exports.cssCase = function(str) {
return str.replace(/[A-Z]/g, '-$&').toLowerCase();
};
/**
* Iterate over each DOM element without creating intermediary Cheerio instances.
*
* This is indented for use internally to avoid otherwise unnecessary memory pressure introduced
* by _make.
*/
exports.domEach = function(cheerio, fn) {
var i = 0, len = cheerio.length;
while (i < len && fn(i, cheerio[i]) !== false) ++i;
return cheerio;
};

View File

@ -1,5 +0,0 @@
language: node_js
node_js:
- 0.8
- "0.10"
- 0.11

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,57 +0,0 @@
#CSSselect [![Build Status](https://secure.travis-ci.org/fb55/CSSselect.png?branch=master)](http://travis-ci.org/fb55/CSSselect)
a CSS selector compiler/engine
##What?
CSSselect turns CSS selectors into functions that tests if elements match them. When searching for elements, testing is executed "from the top", similar to how browsers execute CSS selectors.
In its default configuration, CSSselect queries the DOM structure of the [`domhandler`](https://github.com/fb55/domhandler) module.
##API
```js
var CSSselect = require("CSSselect");
```
####`CSSselect(query, elems)`
- `query` can be either a function or a string. If it's a string, the string is compiled as a CSS selector.
- `elems` can be either an array of elements, or a single element. If it is an element, its children will be used (so we're working with an array again).
Queries `elems`, returns an array containing all matches.
Aliases: `CSSselect.selectAll(query, elems)`, `CSSselect.iterate(query, elems)`.
####`CSSselect.compile(query)`
Compiles the query, returns the function.
####`CSSselect.is(elem, query)`
Tests whether or not an element is matched by `query`. `query` can be either a CSS selector or a function.
####`CSSselect.selectOne(query, elems)`
Arguments are the same as for `CSSselect(query, elems)`. Only returns the first match, or `null` if there was no match.
##Why?
The common approach of executing CSS selectors (used eg. by [`Sizzle`](https://github.com/jquery/sizzle), [`nwmatcher`](https://github.com/dperini/nwmatcher/) and [`qwery`](https://github.com/ded/qwery)) is to execute every component of the selector in order, from left to right. The selector `a b` for example will first look for `a` elements, then search these for `b` elements.
While this works, it has some downsides: Children of `a`s will be checked multiple times, first, to check if they are also `a`s, then, for every superior `a` once, if they are `b`s. Using [Big O notation](http://en.wikipedia.org/wiki/Big_O_notation), that would be `O(n^2)`.
The far more efficient approach is to first look for `b` elements, then check if they have superior `a` elements: Using big O notation again, that would be `O(n)`.
And that's exactly what CSSselect does.
##How?
By stacking functions!
_//TODO: Better explanation. For now, if you're interested, have a look at the source code._
---
License: BSD-like

View File

@ -1,67 +0,0 @@
function isTag(elem){
return elem.nodeType === 1;
}
function getChildren(elem){
return Array.prototype.slice.call(elem.childNodes, 0);
}
function getParent(elem){
return elem.parentElement;
}
module.exports = {
isTag: isTag,
getSiblings: function(elem){
var parent = getParent(elem);
return parent && getChildren(parent);
},
getChildren: getChildren,
getParent: getParent,
getAttributeValue: function(elem, name){
return elem.attributes[name].value;
},
hasAttrib: function(elem, name){
return name in elem.attributes;
},
getName: function(elem){
return elem.tagName.toLowerCase();
},
findOne: function findOne(test, arr){
var elem = null;
for(var i = 0, l = arr.length; i < l && !elem; i++){
if(test(arr[i])){
elem = arr[i];
} else {
var childs = getChildren(arr[i]);
if(childs && childs.length > 0){
elem = findOne(test, childs);
}
}
}
return elem;
},
findAll: function findAll(test, elems){
var result = [];
for(var i = 0, j = elems.length; i < j; i++){
if(!isTag(elems[i])) continue;
if(test(elems[i])) result.push(elems[i]);
var childs = getChildren(elems[i]);
if(childs) result = result.concat(findAll(test, childs));
}
return result;
},
//https://github.com/ded/qwery/blob/master/pseudos/qwery-pseudos.js#L47-54
getText: function getText(elem) {
var str = "",
childs = getChildren(elem);
if(!childs) return str;
for(var i = 0; i < childs.length; i++){
if(isTag(childs[i])) str += elem.textContent || elem.innerText || getText(childs[i]);
}
return str;
}
};

View File

@ -1,54 +0,0 @@
"use strict";
module.exports = CSSselect;
var Pseudos = require("./lib/pseudos.js"),
DomUtils = require("domutils"),
findOne = DomUtils.findOne,
findAll = DomUtils.findAll,
getChildren = DomUtils.getChildren,
removeSubsets = DomUtils.removeSubsets,
falseFunc = require("./lib/basefunctions.js").falseFunc,
compile = require("./lib/compile.js"),
compileUnsafe = compile.compileUnsafe;
function getSelectorFunc(searchFunc){
return function select(query, elems, options){
if(typeof query !== "function") query = compileUnsafe(query, options);
if(!Array.isArray(elems)) elems = getChildren(elems);
else elems = removeSubsets(elems);
return searchFunc(query, elems);
};
}
var selectAll = getSelectorFunc(function selectAll(query, elems){
return (query === falseFunc || !elems || elems.length === 0) ? [] : findAll(query, elems);
});
var selectOne = getSelectorFunc(function selectOne(query, elems){
return (query === falseFunc || !elems || elems.length === 0) ? null : findOne(query, elems);
});
function is(elem, query, options){
return (typeof query === "function" ? query : compile(query, options))(elem);
}
/*
the exported interface
*/
function CSSselect(query, elems, options){
return selectAll(query, elems, options);
}
CSSselect.compile = compile;
CSSselect.filters = Pseudos.filters;
CSSselect.pseudos = Pseudos.pseudos;
CSSselect.selectAll = selectAll;
CSSselect.selectOne = selectOne;
CSSselect.is = is;
//legacy methods (might be removed)
CSSselect.parse = compile;
CSSselect.iterate = selectAll;

View File

@ -1,178 +0,0 @@
var DomUtils = require("domutils"),
hasAttrib = DomUtils.hasAttrib,
getAttributeValue = DomUtils.getAttributeValue,
falseFunc = require("./basefunctions.js").falseFunc;
//https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js#L469
var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g;
/*
attribute selectors
*/
var attributeRules = {
__proto__: null,
equals: function(next, data){
var name = data.name,
value = data.value;
if(data.ignoreCase){
value = value.toLowerCase();
return function equalsIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() === value && next(elem);
};
}
return function equals(elem){
return getAttributeValue(elem, name) === value && next(elem);
};
},
hyphen: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
if(data.ignoreCase){
value = value.toLowerCase();
return function hyphenIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null &&
(attr.length === len || attr.charAt(len) === "-") &&
attr.substr(0, len).toLowerCase() === value &&
next(elem);
};
}
return function hyphen(elem){
var attr = getAttributeValue(elem, name);
return attr != null &&
attr.substr(0, len) === value &&
(attr.length === len || attr.charAt(len) === "-") &&
next(elem);
};
},
element: function(next, data){
var name = data.name,
value = data.value;
if(/\s/.test(value)){
return falseFunc;
}
value = value.replace(reChars, "\\$&");
var pattern = "(?:^|\\s)" + value + "(?:$|\\s)",
flags = data.ignoreCase ? "i" : "",
regex = new RegExp(pattern, flags);
return function element(elem){
var attr = getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
},
exists: function(next, data){
var name = data.name;
return function exists(elem){
return hasAttrib(elem, name) && next(elem);
};
},
start: function(next, data){
var name = data.name,
value = data.value,
len = value.length;
if(len === 0){
return falseFunc;
}
if(data.ignoreCase){
value = value.toLowerCase();
return function startIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem);
};
}
return function start(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(0, len) === value && next(elem);
};
},
end: function(next, data){
var name = data.name,
value = data.value,
len = -value.length;
if(len === 0){
return falseFunc;
}
if(data.ignoreCase){
value = value.toLowerCase();
return function endIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(len).toLowerCase() === value && next(elem);
};
}
return function end(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.substr(len) === value && next(elem);
};
},
any: function(next, data){
var name = data.name,
value = data.value;
if(value === ""){
return falseFunc;
}
if(data.ignoreCase){
var regex = new RegExp(value.replace(reChars, "\\$&"), "i");
return function anyIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && regex.test(attr) && next(elem);
};
}
return function any(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.indexOf(value) >= 0 && next(elem);
};
},
not: function(next, data){
var name = data.name,
value = data.value;
if(value === ""){
return function notEmpty(elem){
return !!getAttributeValue(elem, name) && next(elem);
};
} else if(data.ignoreCase){
value = value.toLowerCase();
return function notIC(elem){
var attr = getAttributeValue(elem, name);
return attr != null && attr.toLowerCase() !== value && next(elem);
};
}
return function not(elem){
return getAttributeValue(elem, name) !== value && next(elem);
};
}
};
module.exports = {
compile: function(next, data){
return attributeRules[data.action](next, data);
},
rules: attributeRules
};

View File

@ -1,8 +0,0 @@
module.exports = {
trueFunc: function trueFunc(){
return true;
},
falseFunc: function falseFunc(){
return false;
}
};

View File

@ -1,84 +0,0 @@
/*
compiles a selector to an executable function
*/
module.exports = compile;
module.exports.compileUnsafe = compileUnsafe;
var parse = require("CSSwhat"),
DomUtils = require("domutils"),
isTag = DomUtils.isTag,
Rules = require("./general.js"),
sortRules = require("./sort.js"),
BaseFuncs = require("./basefunctions.js"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
function compile(selector, options){
var next = compileUnsafe(selector, options);
return function base(elem){
return isTag(elem) && next(elem);
};
}
function compileUnsafe(selector, options){
return parse(selector, options)
.map(compileRules)
.reduce(reduceRules, falseFunc);
}
function compileRules(arr){
if(arr.length === 0) return falseFunc;
return sortRules(arr).reduce(function(func, rule){
if(func === falseFunc) return func;
return Rules[rule.type](func, rule);
}, trueFunc);
}
function reduceRules(a, b){
if(b === falseFunc || a === trueFunc){
return a;
}
if(a === falseFunc || b === trueFunc){
return b;
}
return function combine(elem){
return a(elem) || b(elem);
};
}
//:not and :has have to compile selectors
//doing this in lib/pseudos.js would lead to circular dependencies,
//so we add them here
var Pseudos = require("./pseudos.js"),
filters = Pseudos.filters,
isParent = Pseudos.pseudos.parent,
existsOne = DomUtils.existsOne,
getChildren = DomUtils.getChildren;
filters.not = function(next, select){
var func = compileUnsafe(select);
if(func === falseFunc) return next;
if(func === trueFunc) return falseFunc;
return function(elem){
return !func(elem) && next(elem);
};
};
filters.has = function(next, selector){
var func = compile(selector);
if(func === falseFunc) return falseFunc;
if(func === trueFunc) return function(elem){
return isParent(elem) && next(elem);
};
return function has(elem){
return next(elem) && existsOne(func, getChildren(elem));
};
};

View File

@ -1,80 +0,0 @@
var DomUtils = require("domutils"),
isTag = DomUtils.isTag,
getParent = DomUtils.getParent,
getChildren = DomUtils.getChildren,
getSiblings = DomUtils.getSiblings,
getName = DomUtils.getName;
/*
all available rules
*/
module.exports = {
__proto__: null,
attribute: require("./attributes.js").compile,
pseudo: require("./pseudos.js").compile,
//tags
tag: function(next, data){
var name = data.name;
return function tag(elem){
return getName(elem) === name && next(elem);
};
},
//traversal
descendant: function(next){
return function descendant(elem){
var found = false;
while(!found && (elem = getParent(elem))){
found = next(elem);
}
return found;
};
},
parent: function(next){
return function parent(elem){
return getChildren(elem).some(next);
};
},
child: function(next){
return function child(elem){
var parent = getParent(elem);
return !!parent && next(parent);
};
},
sibling: function(next){
return function sibling(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
if(next(siblings[i])) return true;
}
}
return false;
};
},
adjacent: function(next){
return function adjacent(elem){
var siblings = getSiblings(elem),
lastElement;
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
lastElement = siblings[i];
}
}
return !!lastElement && next(lastElement);
};
},
universal: function(next){
return next;
}
};

View File

@ -1,84 +0,0 @@
var BaseFuncs = require("./basefunctions.js"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
module.exports = function nthCheck(formula){
return compile(parse(formula));
};
module.exports.parse = parse;
module.exports.compile = compile;
//following http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
//[ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]?
var re_nthElement = /^([+\-]?\d*n)?\s*(?:([+\-]?)\s*(\d+))?$/;
/*
parses a nth-check formula, returns an array of two numbers
*/
function parse(formula){
formula = formula.trim().toLowerCase();
if(formula === "even"){
return [2, 0];
} else if(formula === "odd"){
return [2, 1];
} else {
var parsed = formula.match(re_nthElement);
if(!parsed){
throw new SyntaxError("n-th rule couldn't be parsed ('" + formula + "')");
}
var a;
if(parsed[1]){
a = parseInt(parsed[1], 10);
if(!a){
if(parsed[1].charAt(0) === "-") a = -1;
else a = 1;
}
} else a = 0;
return [
a,
parsed[3] ? parseInt((parsed[2] || "") + parsed[3], 10) : 0
];
}
}
/*
returns a function that checks if an elements index matches the given rule
highly optimized to return the fastest solution
*/
function compile(parsed){
var a = parsed[0],
b = parsed[1] - 1;
//when b <= 0, a*n won't be possible for any matches when a < 0
//besides, the specification says that no element is matched when a and b are 0
if(b < 0 && a <= 0) return falseFunc;
//when a is in the range -1..1, it matches any element (so only b is checked)
if(a ===-1) return function(pos){ return pos <= b; };
if(a === 0) return function(pos){ return pos === b; };
//when b <= 0 and a === 1, they match any element
if(a === 1) return b < 0 ? trueFunc : function(pos){ return pos >= b; };
//when a > 0, modulo can be used to check if there is a match
var bMod = b % a;
if(bMod < 0) bMod += a;
if(a > 1){
return function(pos){
return pos >= b && pos % a === bMod;
};
}
a *= -1; //make `a` positive
return function(pos){
return pos <= b && pos % a === bMod;
};
}

View File

@ -1,338 +0,0 @@
/*
pseudo selectors
---
they are available in two forms:
* filters called when the selector
is compiled and return a function
that needs to return next()
* pseudos get called on execution
they need to return a boolean
*/
var DomUtils = require("domutils"),
isTag = DomUtils.isTag,
getText = DomUtils.getText,
getParent = DomUtils.getParent,
getChildren = DomUtils.getChildren,
getSiblings = DomUtils.getSiblings,
hasAttrib = DomUtils.hasAttrib,
getName = DomUtils.getName,
getAttribute= DomUtils.getAttributeValue,
getNCheck = require("./nth-check.js"),
checkAttrib = require("./attributes.js").rules.equals,
BaseFuncs = require("./basefunctions.js"),
trueFunc = BaseFuncs.trueFunc,
falseFunc = BaseFuncs.falseFunc;
//helper methods
function getFirstElement(elems){
for(var i = 0; elems && i < elems.length; i++){
if(isTag(elems[i])) return elems[i];
}
}
function getAttribFunc(name, value){
var data = {name: name, value: value};
return function attribFunc(next){
return checkAttrib(next, data);
};
}
function getChildFunc(next){
return function(elem){
return !!getParent(elem) && next(elem);
};
}
var filters = {
contains: function(next, text){
if(
(text.charAt(0) === "\"" || text.charAt(0) === "'") &&
text.charAt(0) === text.substr(-1)
){
text = text.slice(1, -1);
}
return function contains(elem){
return getText(elem).indexOf(text) >= 0 && next(elem);
};
},
//location specific methods
//first- and last-child methods return as soon as they find another element
"first-child": function(next){
return function firstChild(elem){
return getFirstElement(getSiblings(elem)) === elem && next(elem);
};
},
"last-child": function(next){
return function lastChild(elem){
var siblings = getSiblings(elem);
for(var i = siblings.length - 1; i >= 0; i--){
if(siblings[i] === elem) return next(elem);
if(isTag(siblings[i])) break;
}
return false;
};
},
"first-of-type": function(next){
return function firstOfType(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) return next(elem);
if(getName(siblings[i]) === getName(elem)) break;
}
}
return false;
};
},
"last-of-type": function(next){
return function lastOfType(elem){
var siblings = getSiblings(elem);
for(var i = siblings.length-1; i >= 0; i--){
if(isTag(siblings[i])){
if(siblings[i] === elem) return next(elem);
if(getName(siblings[i]) === getName(elem)) break;
}
}
return false;
};
},
"only-of-type": function(next){
return function onlyOfType(elem){
var siblings = getSiblings(elem);
for(var i = 0, j = siblings.length; i < j; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) continue;
if(getName(siblings[i]) === getName(elem)) return false;
}
}
return next(elem);
};
},
"only-child": function(next){
return function onlyChild(elem){
var siblings = getSiblings(elem);
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i]) && siblings[i] !== elem) return false;
}
return next(elem);
};
},
"nth-child": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthChild(elem){
var siblings = getSiblings(elem);
for(var i = 0, pos = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
else pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-child": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthLastChild(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = siblings.length - 1; i >= 0; i--){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
else pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-of-type": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthOfType(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem) break;
if(getName(siblings[i]) === getName(elem)) pos++;
}
}
return func(pos) && next(elem);
};
},
"nth-last-of-type": function(next, rule){
var func = getNCheck(rule);
if(func === falseFunc) return func;
if(func === trueFunc) return getChildFunc(next);
return function nthLastOfType(elem){
var siblings = getSiblings(elem);
for(var pos = 0, i = siblings.length - 1; i >= 0; i--){
if(siblings[i] === elem) break;
if(getName(siblings[i]) === getName(elem)) pos++;
}
return func(pos) && next(elem);
};
},
//jQuery extensions (others follow as pseudos)
checkbox: getAttribFunc("type", "checkbox"),
file: getAttribFunc("type", "file"),
password: getAttribFunc("type", "password"),
radio: getAttribFunc("type", "radio"),
reset: getAttribFunc("type", "reset"),
image: getAttribFunc("type", "image"),
submit: getAttribFunc("type", "submit")
};
//while filters are precompiled, pseudos get called when they are needed
var pseudos = {
root: function(elem){
return !getParent(elem);
},
empty: function(elem){
return !getChildren(elem).some(function(elem){
return isTag(elem) || elem.type === "text";
});
},
//forms
//to consider: :target, :enabled
selected: function(elem){
if(hasAttrib(elem, "selected")) return true;
else if(getName(elem) !== "option") return false;
//the first <option> in a <select> is also selected
var parent = getParent(elem);
if(!parent || getName(parent) !== "select") return false;
var siblings = getChildren(parent),
sawElem = false;
for(var i = 0; i < siblings.length; i++){
if(isTag(siblings[i])){
if(siblings[i] === elem){
sawElem = true;
} else if(!sawElem){
return false;
} else if(hasAttrib(siblings[i], "selected")){
return false;
}
}
}
return sawElem;
},
disabled: function(elem){
return hasAttrib(elem, "disabled");
},
enabled: function(elem){
return !hasAttrib(elem, "disabled");
},
checked: function(elem){
return hasAttrib(elem, "checked") || pseudos.selected(elem);
},
//jQuery extensions
//:parent is the inverse of :empty
parent: function(elem){
return !pseudos.empty(elem);
},
header: function(elem){
var name = getName(elem);
return name === "h1" ||
name === "h2" ||
name === "h3" ||
name === "h4" ||
name === "h5" ||
name === "h6";
},
button: function(elem){
var name = getName(elem);
return name === "button" ||
name === "input" &&
getAttribute(elem, "type") === "button";
},
input: function(elem){
var name = getName(elem);
return name === "input" ||
name === "textarea" ||
name === "select" ||
name === "button";
},
text: function(elem){
var attr;
return getName(elem) === "input" && (
!(attr = getAttribute(elem, "type")) ||
attr.toLowerCase() === "text"
);
}
};
function verifyArgs(func, name, subselect){
if(subselect === null){
if(func.length > 1){
throw new SyntaxError("pseudo-selector :" + name + " requires an argument");
}
} else {
if(func.length === 1){
throw new SyntaxError("pseudo-selector :" + name + " doesn't have any arguments");
}
}
}
module.exports = {
compile: function(next, data){
var name = data.name,
subselect = data.data;
if(typeof filters[name] === "function"){
verifyArgs(filters[name], name, subselect);
return filters[name](next, subselect);
} else if(typeof pseudos[name] === "function"){
var func = pseudos[name];
verifyArgs(func, name, subselect);
return function pseudoArgs(elem){
return func(elem, subselect) && next(elem);
};
} else {
throw new SyntaxError("unmatched pseudo-class :" + name);
}
},
filters: filters,
pseudos: pseudos
};

View File

@ -1,59 +0,0 @@
module.exports = sortByProcedure;
/*
sort the parts of the passed selector,
as there is potential for optimization
(some types of selectors are faster than others)
*/
var ATTRIBUTE = 1;
var procedure = {
__proto__: null,
universal: 5, //should be last so that it can be ignored
tag: 3, //very quick test
attribute: ATTRIBUTE,
pseudo: 0, //can be pretty expensive (especially :has)
//everything else shouldn't be moved
descendant: -1,
child: -1,
parent: -1,
sibling: -1,
adjacent: -1
};
var attributes = {
__proto__: null,
exists: 8,
equals: 7,
not: 6,
start: 5,
end: 4,
any: 3,
hyphen: 2,
element: 1
};
function sortByProcedure(arr){
for(var i = 1; i < arr.length; i++){
var procNew = procedure[arr[i].type];
if(procNew < 0) continue;
for(var j = i - 1; j >= 0; j--){
if(
procNew > procedure[arr[j].type] || !(
procNew === ATTRIBUTE &&
procedure[arr[j].type] === ATTRIBUTE &&
attributes[arr[i].action] <= attributes[arr[j].action]
)
) break;
var tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
}
}
return arr;
}

View File

@ -1,5 +0,0 @@
language: node_js
node_js:
- 0.8
- "0.10"
- 0.11

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,182 +0,0 @@
"use strict";
module.exports = parse;
var re_ws = /^\s/,
re_name = /^(?:\\.|[\w\-\u00c0-\uFFFF])+/,
re_escape = /\\([\da-f]{1,6}\s?|(\s)|.)/ig,
//modified version of https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L87
re_attr = /^\s*((?:\\.|[\w\u00c0-\uFFFF\-])+)\s*(?:(\S?)=\s*(?:(['"])(.*?)\3|(#?(?:\\.|[\w\u00c0-\uFFFF\-])*)|)|)\s*(i)?\]/;
var actionTypes = {
__proto__: null,
"undefined": "exists",
"": "equals",
"~": "element",
"^": "start",
"$": "end",
"*": "any",
"!": "not",
"|": "hyphen"
};
var simpleSelectors = {
__proto__: null,
">": "child",
"<": "parent",
"~": "sibling",
"+": "adjacent"
};
var attribSelectors = {
__proto__: null,
"#": ["id", "equals"],
".": ["class", "element"]
};
//unescape function taken from https://github.com/jquery/sizzle/blob/master/src/sizzle.js#L139
function funescape( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ?
escaped :
// BMP codepoint
high < 0 ?
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
}
function unescapeCSS(str){
return str.replace(re_escape, funescape);
}
function getClosingPos(selector){
var pos = 1, counter = 1, len = selector.length;
for(; counter > 0 && pos < len; pos++){
if(selector.charAt(pos) === "(") counter++;
else if(selector.charAt(pos) === ")") counter--;
}
return pos;
}
function parse(selector, options){
selector = (selector + "").trimLeft();
var subselects = [],
tokens = [],
sawWS = false,
data, firstChar, name;
function getName(){
var sub = selector.match(re_name)[0];
selector = selector.substr(sub.length);
return unescapeCSS(sub);
}
while(selector !== ""){
if(re_name.test(selector)){
if(sawWS){
tokens.push({type: "descendant"});
sawWS = false;
}
name = getName();
if(!options || ("lowerCaseTags" in options ? options.lowerCaseTags : !options.xmlMode)){
name = name.toLowerCase();
}
tokens.push({type: "tag", name: name});
} else if(re_ws.test(selector)){
sawWS = true;
selector = selector.trimLeft();
} else {
firstChar = selector.charAt(0);
selector = selector.substr(1);
if(firstChar in simpleSelectors){
tokens.push({type: simpleSelectors[firstChar]});
selector = selector.trimLeft();
sawWS = false;
continue;
} else if(firstChar === ","){
if(tokens.length === 0){
throw new SyntaxError("empty sub-selector");
}
subselects.push(tokens);
tokens = [];
selector = selector.trimLeft();
sawWS = false;
continue;
} else if(sawWS){
tokens.push({type: "descendant"});
sawWS = false;
}
if(firstChar === "*"){
tokens.push({type: "universal"});
} else if(firstChar in attribSelectors){
tokens.push({
type: "attribute",
name: attribSelectors[firstChar][0],
action: attribSelectors[firstChar][1],
value: getName(),
ignoreCase: false
});
} else if(firstChar === "["){
data = selector.match(re_attr);
if(!data){
throw new SyntaxError("Malformed attribute selector: " + selector);
}
selector = selector.substr(data[0].length);
name = unescapeCSS(data[1]);
if(
!options || (
"lowerCaseAttributeNames" in options ?
options.lowerCaseAttributeNames :
!options.xmlMode
)
){
name = name.toLowerCase();
}
tokens.push({
type: "attribute",
name: name,
action: actionTypes[data[2]],
value: unescapeCSS(data[4] || data[5] || ""),
ignoreCase: !!data[6]
});
} else if(firstChar === ":"){
//if(selector.charAt(0) === ":"){} //TODO pseudo-element
name = getName().toLowerCase();
data = null;
if(selector.charAt(0) === "("){
var pos = getClosingPos(selector);
data = selector.substr(1, pos - 2);
selector = selector.substr(pos);
}
tokens.push({type: "pseudo", name: name, data: data});
} else {
//otherwise, the parser needs to throw or it would enter an infinite loop
throw new SyntaxError("Unmatched selector: " + firstChar + selector);
}
}
}
if(subselects.length > 0 && tokens.length === 0){
throw new SyntaxError("empty sub-selector");
}
subselects.push(tokens);
return subselects;
}

View File

@ -1,52 +0,0 @@
{
"author": {
"name": "Felix Böhm",
"email": "me@feedic.com",
"url": "http://feedic.com"
},
"name": "CSSwhat",
"description": "a CSS selector parser",
"version": "0.4.7",
"repository": {
"url": "https://github.com/FB55/CSSwhat"
},
"main": "./index.js",
"scripts": {
"test": "node tests/test.js && jshint *.js"
},
"dependencies": {},
"devDependencies": {
"jshint": "2"
},
"optionalDependencies": {},
"engines": {
"node": "*"
},
"license": "BSD-like",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"readme": "#CSSwhat [![Build Status](https://secure.travis-ci.org/fb55/CSSwhat.png?branch=master)](http://travis-ci.org/fb55/CSSwhat)\n\na CSS selector parser\n\n##Example\n\n```js\nrequire('CSSwhat')('foo[bar]:baz')\n\n~> [ [ { type: 'tag', name: 'foo' },\n { type: 'attribute',\n name: 'bar',\n action: 'exists',\n value: '',\n ignoreCase: false },\n { type: 'pseudo',\n name: 'baz',\n data: null } ] ]\n```\n\n##API\n\n__`CSSwhat(selector, options)` - Parses `str`, with the passed `options`.__\n\nThe function returns a two-dimensional array. The first array represents subselects separated by commas (eg. `sub1, sub2`), the second contains the relevant tokens for that selector. Possible token types are:\n\nname | attributes | example | output\n---- | ---------- | ------- | ------\n`tag`| `name` | `div` | `{ type: 'tag', name: 'div' }`\n`universal`| - | `*` | `{ type: 'universal' }`\n`pseudo`| `name`, `data`|`:name(data)`| `{ type: 'pseudo', name: 'name', data: 'data' }`\n`pseudo`| `name`, `data`|`:name`| `{ type: 'pseudo', name: 'name', data: null }`\n`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr]`|`{ type: 'attribute', name: 'attr', action: 'exists', value: '', ignoreCase: false }`\n`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr=val]`|`{ type: 'attribute', name: 'attr', action: 'equals', value: 'val', ignoreCase: false }`\n`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr^=val]`|`{ type: 'attribute', name: 'attr', action: 'start', value: 'val', ignoreCase: false }`\n`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr$=val]`|`{ type: 'attribute', name: 'attr', action: 'end', value: 'val', ignoreCase: false }`\n\n//TODO complete list\n\n__Options:__\n\n- `xmlMode`: When enabled, tagnames will be case-sensitive (ie. the output won't be lowercased).\n\n---\n\nLicense: BSD-like\n",
"readmeFilename": "readme.md",
"bugs": {
"url": "https://github.com/FB55/CSSwhat/issues"
},
"_id": "CSSwhat@0.4.7",
"_from": "CSSwhat@0.4"
}

View File

@ -1,46 +0,0 @@
#CSSwhat [![Build Status](https://secure.travis-ci.org/fb55/CSSwhat.png?branch=master)](http://travis-ci.org/fb55/CSSwhat)
a CSS selector parser
##Example
```js
require('CSSwhat')('foo[bar]:baz')
~> [ [ { type: 'tag', name: 'foo' },
{ type: 'attribute',
name: 'bar',
action: 'exists',
value: '',
ignoreCase: false },
{ type: 'pseudo',
name: 'baz',
data: null } ] ]
```
##API
__`CSSwhat(selector, options)` - Parses `str`, with the passed `options`.__
The function returns a two-dimensional array. The first array represents subselects separated by commas (eg. `sub1, sub2`), the second contains the relevant tokens for that selector. Possible token types are:
name | attributes | example | output
---- | ---------- | ------- | ------
`tag`| `name` | `div` | `{ type: 'tag', name: 'div' }`
`universal`| - | `*` | `{ type: 'universal' }`
`pseudo`| `name`, `data`|`:name(data)`| `{ type: 'pseudo', name: 'name', data: 'data' }`
`pseudo`| `name`, `data`|`:name`| `{ type: 'pseudo', name: 'name', data: null }`
`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr]`|`{ type: 'attribute', name: 'attr', action: 'exists', value: '', ignoreCase: false }`
`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr=val]`|`{ type: 'attribute', name: 'attr', action: 'equals', value: 'val', ignoreCase: false }`
`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr^=val]`|`{ type: 'attribute', name: 'attr', action: 'start', value: 'val', ignoreCase: false }`
`attribute`|`name`, `action`, `value`, `ignoreCase`|`[attr$=val]`|`{ type: 'attribute', name: 'attr', action: 'end', value: 'val', ignoreCase: false }`
//TODO complete list
__Options:__
- `xmlMode`: When enabled, tagnames will be case-sensitive (ie. the output won't be lowercased).
---
License: BSD-like

File diff suppressed because it is too large Load Diff

View File

@ -1,392 +0,0 @@
var assert = require("assert"),
CSSwhat = require("../");
var tests = [
//tag names
[
'div',
[
[
{
'type': 'tag',
'name': 'div'
}
]
],
'simple tag'
],
[
'*',
[
[
{
'type': 'universal'
}
]
],
'universal'
],
//traversal
[
'div div',
[
[
{
'type': 'tag',
'name': 'div'
},
{
'type': 'descendant'
},
{
'type': 'tag',
'name': 'div'
}
]
],
'descendant'
],
[
'div\t \n \tdiv',
[
[
{
'type': 'tag',
'name': 'div'
},
{
'type': 'descendant'
},
{
'type': 'tag',
'name': 'div'
}
]
],
'descendant /w whitespace'
],
[
'div + div',
[
[
{
'type': 'tag',
'name': 'div'
},
{
'type': 'adjacent'
},
{
'type': 'tag',
'name': 'div'
}
]
],
'adjacent'
],
[
'div ~ div',
[
[
{
'type': 'tag',
'name': 'div'
},
{
'type': 'sibling'
},
{
'type': 'tag',
'name': 'div'
}
]
],
'sibling'
],
[
'p < div',
[
[
{
'type': 'tag',
'name': 'p'
},
{
'type': 'parent'
},
{
'type': 'tag',
'name': 'div'
}
]
],
'parent'
],
//Escaped whitespace
[
'#\\ > a ',
[
[
{
'type': 'attribute',
'action': 'equals',
'name': 'id',
'value': ' ',
'ignoreCase': false
},
{
'type': 'child'
},
{
'type': 'tag',
'name': 'a'
}
]
],
'Space between escaped space and combinator'
],
[
'.\\ ',
[
[
{
'type': 'attribute',
'name': 'class',
'action': 'element',
'value': ' ',
'ignoreCase': false
}
]
],
'Space after escaped space'
],
[
'\\61 ',
[
[
{
'type': 'tag',
'name': 'a'
}
]
],
'Numeric escape with space (BMP)'
],
[
'\\1d306\\01d306',
[
[
{
'type': 'tag',
'name': '\uD834\uDF06\uD834\uDF06'
}
]
],
'Numeric escape (outside BMP)'
],
//attributes
[
'[name^=\'foo[\']',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'start',
'value': 'foo[',
'ignoreCase': false
}
]
],
'quoted attribute'
],
[
'[name^=\'foo[bar]\']',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'start',
'value': 'foo[bar]',
'ignoreCase': false
}
]
],
'quoted attribute'
],
[
'[name$=\'[bar]\']',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'end',
'value': '[bar]',
'ignoreCase': false
}
]
],
'quoted attribute'
],
[
'[href *= \'google\']',
[
[
{
'type': 'attribute',
'name': 'href',
'action': 'any',
'value': 'google',
'ignoreCase': false
}
]
],
'quoted attribute with spaces'
],
[
'[name=foo\\.baz]',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'equals',
'value': 'foo.baz',
'ignoreCase': false
}
]
],
'attribute with escaped dot'
],
[
'[name=foo\\[bar\\]]',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'equals',
'value': 'foo[bar]',
'ignoreCase': false
}
]
],
'attribute with escaped square brackets'
],
[
'[xml\\:test]',
[
[
{
'type': 'attribute',
'name': 'xml:test',
'action': 'exists',
'value': '',
'ignoreCase': false
}
]
],
'escaped attribute'
],
[
'[name="foo ~ < > , bar" i]',
[
[
{
'type': 'attribute',
'name': 'name',
'action': 'equals',
'value': 'foo ~ < > , bar',
'ignoreCase': true
}
]
],
'attribute with previously normalized characters'
],
//pseudo selectors
[
':foo',
[
[
{
'type': 'pseudo',
'name': 'foo',
'data': null
}
]
],
'pseudo selector without any data'
],
[
':bar(baz)',
[
[
{
'type': 'pseudo',
'name': 'bar',
'data': 'baz'
}
]
],
'pseudo selector with data'
],
[
':contains(\'(foo)\')',
[
[
{
'type': 'pseudo',
'name': 'contains',
'data': '\'(foo)\''
}
]
],
'pseudo selector with data'
],
//multiple selectors
[
'a , b',
[
[
{
'type': 'tag',
'name': 'a'
}
],
[
{
'type': 'tag',
'name': 'b'
}
]
],
'multiple selectors'
]
];
tests.forEach(function(arr, i){
arr[0] = CSSwhat(arr[0]);
assert.deepEqual.apply(null, arr);
console.log("\t%d: '%s' passed", i + 1, arr[2]);
});
console.log("\nCollected selectors (qwery, sizzle, nwmatcher)...");
var out = require("./out.json");
Object.keys(out).forEach(function(s){
assert.deepEqual(CSSwhat(s), out[s], s);
});
console.log("Passed!");

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,14 +0,0 @@
var DomUtils = module.exports;
[
require("./lib/stringify"),
require("./lib/traversal"),
require("./lib/manipulation"),
require("./lib/querying"),
require("./lib/legacy"),
require("./lib/helpers")
].forEach(function(ext){
Object.keys(ext).forEach(function(key){
DomUtils[key] = ext[key].bind(DomUtils);
});
});

View File

@ -1,31 +0,0 @@
// removeSubsets
// Given an array of nodes, remove any member that is contained by another.
exports.removeSubsets = function(nodes) {
var idx = nodes.length, node, ancestor, replace;
// Check if each node (or one of its ancestors) is already contained in the
// array.
while (--idx > -1) {
node = ancestor = nodes[idx];
// Temporarily remove the node under consideration
nodes[idx] = null;
replace = true;
while (ancestor) {
if (nodes.indexOf(ancestor) > -1) {
replace = false;
nodes.splice(idx, 1);
break;
}
ancestor = ancestor.parent;
}
// If the node has been found to be unique, re-insert it.
if (replace) {
nodes[idx] = node;
}
}
return nodes;
};

View File

@ -1,87 +0,0 @@
var ElementType = require("domelementtype");
var isTag = exports.isTag = ElementType.isTag;
exports.testElement = function(options, element){
for(var key in options){
if(!options.hasOwnProperty(key));
else if(key === "tag_name"){
if(!isTag(element) || !options.tag_name(element.name)){
return false;
}
} else if(key === "tag_type"){
if(!options.tag_type(element.type)) return false;
} else if(key === "tag_contains"){
if(isTag(element) || !options.tag_contains(element.data)){
return false;
}
} else if(!element.attribs || !options[key](element.attribs[key])){
return false;
}
}
return true;
};
var Checks = {
tag_name: function(name){
if(typeof name === "function"){
return function(elem){ return isTag(elem) && name(elem.name); };
} else if(name === "*"){
return isTag;
} else {
return function(elem){ return isTag(elem) && elem.name === name; };
}
},
tag_type: function(type){
if(typeof type === "function"){
return function(elem){ return type(elem.type); };
} else {
return function(elem){ return elem.type === type; };
}
},
tag_contains: function(data){
if(typeof data === "function"){
return function(elem){ return !isTag(elem) && data(elem.data); };
} else {
return function(elem){ return !isTag(elem) && elem.data === data; };
}
}
};
function getAttribCheck(attrib, value){
if(typeof value === "function"){
return function(elem){ return elem.attribs && value(elem.attribs[attrib]); };
} else {
return function(elem){ return elem.attribs && elem.attribs[attrib] === value; };
}
}
function combineFuncs(a, b){
return function(elem){
return a(elem) || b(elem);
};
}
exports.getElements = function(options, element, recurse, limit){
var funcs = Object.keys(options).map(function(key){
var value = options[key];
return key in Checks ? Checks[key](value) : getAttribCheck(key, value);
});
return funcs.length === 0 ? [] : this.filter(
funcs.reduce(combineFuncs),
element, recurse, limit
);
};
exports.getElementById = function(id, element, recurse){
if(!Array.isArray(element)) element = [element];
return this.findOne(getAttribCheck("id", id), element, recurse !== false);
};
exports.getElementsByTagName = function(name, element, recurse, limit){
return this.filter(Checks.tag_name(name), element, recurse, limit);
};
exports.getElementsByTagType = function(type, element, recurse, limit){
return this.filter(Checks.tag_type(type), element, recurse, limit);
};

View File

@ -1,77 +0,0 @@
exports.removeElement = function(elem){
if(elem.prev) elem.prev.next = elem.next;
if(elem.next) elem.next.prev = elem.prev;
if(elem.parent){
var childs = elem.parent.children;
childs.splice(childs.lastIndexOf(elem), 1);
}
};
exports.replaceElement = function(elem, replacement){
var prev = replacement.prev = elem.prev;
if(prev){
prev.next = replacement;
}
var next = replacement.next = elem.next;
if(next){
next.prev = replacement;
}
var parent = replacement.parent = elem.parent;
if(parent){
var childs = parent.children;
childs[childs.lastIndexOf(elem)] = replacement;
}
};
exports.appendChild = function(elem, child){
child.parent = elem;
if(elem.children.push(child) !== 1){
var sibling = elem.children[elem.children.length - 2];
sibling.next = child;
child.prev = sibling;
child.next = null;
}
};
exports.append = function(elem, next){
var parent = elem.parent,
currNext = elem.next;
next.next = currNext;
next.prev = elem;
elem.next = next;
next.parent = parent;
if(currNext){
currNext.prev = next;
if(parent){
var childs = parent.children;
childs.splice(childs.lastIndexOf(currNext), 0, next);
}
} else if(parent){
parent.children.push(next);
}
};
exports.prepend = function(elem, prev){
var parent = elem.parent;
if(parent){
var childs = parent.children;
childs.splice(childs.lastIndexOf(elem), 0, prev);
}
if(elem.prev){
elem.prev.next = prev;
}
prev.parent = parent;
prev.prev = elem.prev;
prev.next = elem;
elem.prev = prev;
};

View File

@ -1,94 +0,0 @@
var isTag = require("domelementtype").isTag;
module.exports = {
filter: filter,
find: find,
findOneChild: findOneChild,
findOne: findOne,
existsOne: existsOne,
findAll: findAll
};
function filter(test, element, recurse, limit){
if(!Array.isArray(element)) element = [element];
if(typeof limit !== "number" || !isFinite(limit)){
limit = Infinity;
}
return find(test, element, recurse !== false, limit);
}
function find(test, elems, recurse, limit){
var result = [], childs;
for(var i = 0, j = elems.length; i < j; i++){
if(test(elems[i])){
result.push(elems[i]);
if(--limit <= 0) break;
}
childs = elems[i].children;
if(recurse && childs && childs.length > 0){
childs = find(test, childs, recurse, limit);
result = result.concat(childs);
limit -= childs.length;
if(limit <= 0) break;
}
}
return result;
}
function findOneChild(test, elems){
for(var i = 0, l = elems.length; i < l; i++){
if(test(elems[i])) return elems[i];
}
return null;
}
function findOne(test, elems){
var elem = null;
for(var i = 0, l = elems.length; i < l && !elem; i++){
if(!isTag(elems[i])){
continue;
} else if(test(elems[i])){
elem = elems[i];
} else if(elems[i].children.length > 0){
elem = findOne(test, elems[i].children);
}
}
return elem;
}
function existsOne(test, elems){
for(var i = 0, l = elems.length; i < l; i++){
if(
isTag(elems[i]) && (
test(elems[i]) || (
elems[i].children.length > 0 &&
existsOne(test, elems[i].children)
)
)
){
return true;
}
}
return false;
}
function findAll(test, elems){
var result = [];
for(var i = 0, j = elems.length; i < j; i++){
if(!isTag(elems[i])) continue;
if(test(elems[i])) result.push(elems[i]);
if(elems[i].children.length > 0){
result = result.concat(findAll(test, elems[i].children));
}
}
return result;
}

View File

@ -1,93 +0,0 @@
var ElementType = require("domelementtype"),
isTag = ElementType.isTag;
module.exports = {
getInnerHTML: getInnerHTML,
getOuterHTML: getOuterHTML,
getText: getText
};
function getInnerHTML(elem){
return elem.children ? elem.children.map(getOuterHTML).join("") : "";
}
//boolean attributes without a value (taken from MatthewMueller/cheerio)
var booleanAttribs = {
__proto__: null,
async: true,
autofocus: true,
autoplay: true,
checked: true,
controls: true,
defer: true,
disabled: true,
hidden: true,
loop: true,
multiple: true,
open: true,
readonly: true,
required: true,
scoped: true,
selected: true
};
var emptyTags = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
link: true,
meta: true,
param: true,
embed: true
};
function getOuterHTML(elem){
switch(elem.type){
case ElementType.Text:
return elem.data;
case ElementType.Comment:
return "<!--" + elem.data + "-->";
case ElementType.Directive:
return "<" + elem.data + ">";
case ElementType.CDATA:
return "<!CDATA " + getInnerHTML(elem) + "]]>";
}
var ret = "<" + elem.name;
if("attribs" in elem){
for(var attr in elem.attribs){
if(elem.attribs.hasOwnProperty(attr)){
ret += " " + attr;
var value = elem.attribs[attr];
if(value == null){
if( !(attr in booleanAttribs) ){
ret += "=\"\"";
}
} else {
ret += "=\"" + value + "\"";
}
}
}
}
if (elem.name in emptyTags && elem.children.length === 0) {
return ret + " />";
} else {
return ret + ">" + getInnerHTML(elem) + "</" + elem.name + ">";
}
}
function getText(elem){
if(Array.isArray(elem)) return elem.map(getText).join("");
if(isTag(elem) || elem.type === ElementType.CDATA) return getText(elem.children);
if(elem.type === ElementType.Text) return elem.data;
return "";
}

View File

@ -1,24 +0,0 @@
var getChildren = exports.getChildren = function(elem){
return elem.children;
};
var getParent = exports.getParent = function(elem){
return elem.parent;
};
exports.getSiblings = function(elem){
var parent = getParent(elem);
return parent ? getChildren(parent) : [elem];
};
exports.getAttributeValue = function(elem, name){
return elem.attribs && elem.attribs[name];
};
exports.hasAttrib = function(elem, name){
return hasOwnProperty.call(elem.attribs, name);
};
exports.getName = function(elem){
return elem.name;
};

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,14 +0,0 @@
//Types of elements found in the DOM
module.exports = {
Text: "text", //Text
Directive: "directive", //<? ... ?>
Comment: "comment", //<!-- ... -->
Script: "script", //<script> tags
Style: "style", //<style> tags
Tag: "tag", //Any tag
CDATA: "cdata", //<![CDATA[ ... ]]>
isTag: function(elem){
return elem.type === "tag" || elem.type === "script" || elem.type === "style";
}
};

View File

@ -1,26 +0,0 @@
{
"name": "domelementtype",
"version": "1.1.1",
"description": "all the types of nodes in htmlparser2's dom",
"main": "index.js",
"repository": {
"type": "git",
"url": "git://github.com/FB55/domelementtype.git"
},
"keywords": [
"dom",
"htmlparser2"
],
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"readme": "all the types of nodes in htmlparser2's dom\n",
"readmeFilename": "readme.md",
"bugs": {
"url": "https://github.com/FB55/domelementtype/issues"
},
"_id": "domelementtype@1.1.1",
"_from": "domelementtype@1",
"scripts": {}
}

View File

@ -1 +0,0 @@
all the types of nodes in htmlparser2's dom

View File

@ -1,54 +0,0 @@
{
"name": "domutils",
"version": "1.4.3",
"description": "utilities for working with htmlparser2's dom",
"main": "index.js",
"directories": {
"test": "tests"
},
"scripts": {
"test": "mocha test/tests/**.js && jshint index.js test/**/*.js lib/*.js"
},
"repository": {
"type": "git",
"url": "git://github.com/FB55/domutils.git"
},
"keywords": [
"dom",
"htmlparser2"
],
"dependencies": {
"domelementtype": "1"
},
"devDependencies": {
"htmlparser2": "~3.3.0",
"domhandler": "2",
"jshint": "~2.3.0",
"mocha": "~1.15.1"
},
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"jshintConfig": {
"proto": true,
"unused": true,
"eqnull": true,
"undef": true,
"quotmark": "double",
"eqeqeq": true,
"trailing": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"readme": "utilities for working with htmlparser2's dom\n",
"readmeFilename": "readme.md",
"bugs": {
"url": "https://github.com/FB55/domutils/issues"
},
"_id": "domutils@1.4.3",
"_from": "domutils@1.4"
}

View File

@ -1 +0,0 @@
utilities for working with htmlparser2's dom

View File

@ -1,6 +0,0 @@
var makeDom = require("./utils").makeDom;
var markup = Array(21).join(
"<?xml><tag1 id='asdf'> <script>text</script> <!-- comment --> <tag2> text </tag1>"
);
module.exports = makeDom(markup);

View File

@ -1,29 +0,0 @@
var makeDom = require("../utils").makeDom;
var assert = require("assert");
describe("helpers", function() {
describe("removeSubsets", function() {
var removeSubsets = require("../..").removeSubsets;
var dom = makeDom("<div><p><span></span></p><p></p></div>")[0];
it("removes identical trees", function() {
var matches = removeSubsets([dom, dom]);
assert.equal(matches.length, 1);
});
it("Removes subsets found first", function() {
var matches = removeSubsets([dom, dom.children[0].children[0]]);
assert.equal(matches.length, 1);
});
it("Removes subsets found last", function() {
var matches = removeSubsets([dom.children[0], dom]);
assert.equal(matches.length, 1);
});
it("Does not remove unique trees", function() {
var matches = removeSubsets([dom.children[0], dom.children[1]]);
assert.equal(matches.length, 2);
});
});
});

View File

@ -1,119 +0,0 @@
var DomUtils = require("../..");
var fixture = require("../fixture");
var assert = require("assert");
// Set up expected structures
var expected = {
idAsdf: fixture[1],
tag2: [],
typeScript: []
};
for (var idx = 0; idx < 20; ++idx) {
expected.tag2.push(fixture[idx*2 + 1].children[5]);
expected.typeScript.push(fixture[idx*2 + 1].children[1]);
}
describe("legacy", function() {
describe("getElements", function() {
var getElements = DomUtils.getElements;
it("returns the node with the specified ID", function() {
assert.deepEqual(
getElements({ id: "asdf" }, fixture, true, 1),
[expected.idAsdf]
);
});
it("returns empty array for unknown IDs", function() {
assert.deepEqual(getElements({ id: "asdfs" }, fixture, true), []);
});
it("returns the nodes with the specified tag name", function() {
assert.deepEqual(
getElements({ tag_name:"tag2" }, fixture, true),
expected.tag2
);
});
it("returns empty array for unknown tag names", function() {
assert.deepEqual(
getElements({ tag_name : "asdfs" }, fixture, true),
[]
);
});
it("returns the nodes with the specified tag type", function() {
assert.deepEqual(
getElements({ tag_type: "script" }, fixture, true),
expected.typeScript
);
});
it("returns empty array for unknown tag types", function() {
assert.deepEqual(
getElements({ tag_type: "video" }, fixture, true),
[]
);
});
});
describe("getElementById", function() {
var getElementById = DomUtils.getElementById;
it("returns the specified node", function() {
assert.equal(
expected.idAsdf,
getElementById("asdf", fixture, true)
);
});
it("returns `null` for unknown IDs", function() {
assert.equal(null, getElementById("asdfs", fixture, true));
});
});
describe("getElementsByTagName", function() {
var getElementsByTagName = DomUtils.getElementsByTagName;
it("returns the specified nodes", function() {
assert.deepEqual(
getElementsByTagName("tag2", fixture, true),
expected.tag2
);
});
it("returns empty array for unknown tag names", function() {
assert.deepEqual(
getElementsByTagName("tag23", fixture, true),
[]
);
});
});
describe("getElementsByTagType", function() {
var getElementsByTagType = DomUtils.getElementsByTagType;
it("returns the specified nodes", function() {
assert.deepEqual(
getElementsByTagType("script", fixture, true),
expected.typeScript
);
});
it("returns empty array for unknown tag types", function() {
assert.deepEqual(
getElementsByTagType("video", fixture, true),
[]
);
});
});
describe("getOuterHTML", function() {
var getOuterHTML = DomUtils.getOuterHTML;
it("Correctly renders the outer HTML", function() {
assert.equal(
getOuterHTML(fixture[1]),
"<tag1 id=\"asdf\"> <script>text</script> <!-- comment --> <tag2> text </tag2></tag1>"
);
});
});
describe("getInnerHTML", function() {
var getInnerHTML = DomUtils.getInnerHTML;
it("Correctly renders the inner HTML", function() {
assert.equal(
getInnerHTML(fixture[1]),
" <script>text</script> <!-- comment --> <tag2> text </tag2>"
);
});
});
});

View File

@ -1,9 +0,0 @@
var htmlparser = require("htmlparser2");
exports.makeDom = function(markup) {
var handler = new htmlparser.DomHandler(),
parser = new htmlparser.Parser(handler);
parser.write(markup);
parser.done();
return handler.dom;
};

View File

@ -1,38 +0,0 @@
{
"name": "CSSselect",
"version": "0.4.1",
"description": "a CSS selector compiler/engine",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"keywords": [
"css",
"selector"
],
"repository": {
"type": "git",
"url": "git://github.com/fb55/CSSselect.git"
},
"dependencies": {
"CSSwhat": "0.4",
"domutils": "1.4"
},
"devDependencies": {
"htmlparser2": "*",
"cheerio-soupselect": "*",
"mocha": "*",
"expect.js": "*"
},
"scripts": {
"test": "mocha"
},
"license": "BSD-like",
"readme": "#CSSselect [![Build Status](https://secure.travis-ci.org/fb55/CSSselect.png?branch=master)](http://travis-ci.org/fb55/CSSselect)\n\na CSS selector compiler/engine\n\n##What?\n\nCSSselect turns CSS selectors into functions that tests if elements match them. When searching for elements, testing is executed \"from the top\", similar to how browsers execute CSS selectors.\n\nIn its default configuration, CSSselect queries the DOM structure of the [`domhandler`](https://github.com/fb55/domhandler) module.\n\n##API\n\n```js\nvar CSSselect = require(\"CSSselect\");\n```\n\n####`CSSselect(query, elems)`\n\n- `query` can be either a function or a string. If it's a string, the string is compiled as a CSS selector.\n- `elems` can be either an array of elements, or a single element. If it is an element, its children will be used (so we're working with an array again).\n\nQueries `elems`, returns an array containing all matches.\n\nAliases: `CSSselect.selectAll(query, elems)`, `CSSselect.iterate(query, elems)`.\n\n####`CSSselect.compile(query)`\n\nCompiles the query, returns the function.\n\n####`CSSselect.is(elem, query)`\n\nTests whether or not an element is matched by `query`. `query` can be either a CSS selector or a function.\n\n####`CSSselect.selectOne(query, elems)`\n\nArguments are the same as for `CSSselect(query, elems)`. Only returns the first match, or `null` if there was no match.\n\n##Why?\n\nThe common approach of executing CSS selectors (used eg. by [`Sizzle`](https://github.com/jquery/sizzle), [`nwmatcher`](https://github.com/dperini/nwmatcher/) and [`qwery`](https://github.com/ded/qwery)) is to execute every component of the selector in order, from left to right. The selector `a b` for example will first look for `a` elements, then search these for `b` elements.\n\nWhile this works, it has some downsides: Children of `a`s will be checked multiple times, first, to check if they are also `a`s, then, for every superior `a` once, if they are `b`s. Using [Big O notation](http://en.wikipedia.org/wiki/Big_O_notation), that would be `O(n^2)`.\n\nThe far more efficient approach is to first look for `b` elements, then check if they have superior `a` elements: Using big O notation again, that would be `O(n)`.\n\nAnd that's exactly what CSSselect does.\n\n##How?\n\nBy stacking functions!\n\n_//TODO: Better explanation. For now, if you're interested, have a look at the source code._\n\n\n---\n\nLicense: BSD-like",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/fb55/CSSselect/issues"
},
"_id": "CSSselect@0.4.1",
"_from": "CSSselect@~0.4.0"
}

View File

@ -1,31 +0,0 @@
var CSSselect = require(".."),
htmlparser = require("htmlparser2"),
assert = require("assert");
function makeDom(markup) {
var handler = new htmlparser.DomHandler(),
parser = new htmlparser.Parser(handler);
parser.write(markup);
parser.done();
return handler.dom;
}
describe("API", function() {
describe("removes duplicates", function() {
it("between identical trees", function() {
var dom = makeDom("<div></div>")[0];
var matches = CSSselect("div", [dom, dom]);
assert.equal(matches.length, 1, "Removes duplicate matches");
});
it("between a superset and subset", function() {
var dom = makeDom("<div><p></p></div>")[0];
var matches = CSSselect("p", [dom, dom.children[0]]);
assert.equal(matches.length, 1, "Removes duplicate matches");
});
it("betweeen a subset and superset", function() {
var dom = makeDom("<div><p></p></div>")[0];
var matches = CSSselect("p", [dom.children[0], dom]);
assert.equal(matches.length, 1, "Removes duplicate matches");
});
});
});

View File

@ -1,2 +0,0 @@
--check-leaks
--reporter spec

View File

@ -1,117 +0,0 @@
var nthCheck = require("../lib/nth-check.js"),
assert = require("assert");
var invalid = ["-", "asdf", "2n+-0", "2+0", "- 1n", "-1 n"];
function parseInvalid(){
invalid.forEach(function(formula){
assert.throws(function(){
nthCheck.parse(formula);
},
SyntaxError,
formula
);
});
}
var valid = {
"1": [ 0, 1 ],
"2": [ 0, 2 ],
"3": [ 0, 3 ],
"5": [ 0, 5 ],
" 1 ": [ 0, 1 ],
" 5 ": [ 0, 5 ],
"+2n + 1": [ 2, 1 ],
"-1": [ 0, -1 ],
"-1n + 3": [ -1, 3 ],
"-1n+3": [ -1, 3 ],
"-n+2": [ -1, 2 ],
"-n+3": [ -1, 3 ],
"0n+3": [ 1, 3 ],
"1n": [ 1, 0 ],
"1n+0": [ 1, 0 ],
"2n": [ 2, 0 ],
"2n + 1": [ 2, 1 ],
"2n+1": [ 2, 1 ],
"3n": [ 3, 0 ],
"3n+0": [ 3, 0 ],
"3n+1": [ 3, 1 ],
"3n+2": [ 3, 2 ],
"3n+3": [ 3, 3 ],
"3n-1": [ 3, -1 ],
"3n-2": [ 3, -2 ],
"3n-3": [ 3, -3 ],
even: [ 2, 0 ],
n: [ 1, 0 ],
"n+2": [ 1, 2 ],
odd: [ 2, 1 ],
//surprisingly, neither sizzle, qwery or nwmatcher cover these cases
"-4n+13": [-4, 13],
"-2n + 12": [-2, 12]
};
function parseValid(){
Object.keys(valid).forEach(function(formula){
assert.deepEqual(nthCheck.parse(formula), valid[formula], formula);
});
}
function testValid(){
Object.keys(valid).forEach(function(formula){
testFormula(valid[formula], formula);
});
}
var LIMIT = 1e3;
var valArray = (function(){
var elems = [];
for(var i = 0; i <= LIMIT; i++) elems.push(i);
return elems;
}());
function testFormula(formula, name){
var filtered = valArray.filter(nthCheck.compile(formula)),
iterated = stupidNth(formula);
try {
assert.deepEqual(filtered, iterated, name);
} catch(e){
e.expected = JSON.stringify(iterated) + " " + name;
e.actual = JSON.stringify(filtered) + " " + name;
throw e;
}
}
function stupidNth(formula, limit){
var a = formula[0],
b = formula[1];
if(a === 0 && b > 0) return [b - 1];
/*
var result = [];
for(var i = b; a > 0 ? i <= limit : i >= 1; i += a){
if(i > 0) result.push(i - 1);
}
return result.sort();
*/
//taken from qwery
return valArray.filter(function(val){
for(var i = b, l = valArray.length; ((a > 0) ? (i <= l) : (i >= 1)); i += a){
if(val === valArray[i - 1]) return true;
}
});
}
describe("nth-checks", function(){
describe("parser", function(){
it("parse invalid", parseInvalid);
it("parse valid", parseValid);
});
it("check values", testValid);
});

View File

@ -1,22 +0,0 @@
Copyright (c) 2007-2013 Diego Perini (http://www.iport.it)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,467 +0,0 @@
/*
taken from https://github.com/dperini/nwmatcher/blob/master/test/scotch/test.js
*/
var DomUtils = require("htmlparser2").DomUtils,
helper = require("../tools/helper.js"),
assert = require("assert"),
path = require("path"),
document = helper.getDocument(path.join(__dirname, "test.html")),
CSSselect = helper.CSSselect;
//Prototype's `$` function
function getById(element){
if(arguments.length === 1){
if(typeof element === "string"){
return DomUtils.getElementById(element, document);
}
return element;
}
else return Array.prototype.map.call(arguments, function(elem){
return getById(elem);
});
}
//NWMatcher methods
var select = function(query, doc){
if(arguments.length === 1 || typeof doc === "undefined") doc = document;
else if(typeof doc === "string") doc = select(doc);
return CSSselect(query, doc);
}, match = CSSselect.is;
var validators = {
assert: assert,
assertEqual: assert.equal,
assertEquivalent: assert.deepEqual,
refute: function refute(a, msg){
assert(!a, msg);
},
assertThrowsException: function(){} //not implemented
};
var runner = {
__name: "",
addGroup: function(name){
this.__name = name;
return this;
},
addTests: function(_, tests){
if(this.__name){
describe(this.__name, run);
this.__name = "";
} else run();
function run(){
Object.keys(tests).forEach(function(name){
it(name, function(){
tests[name].call(validators);
});
});
}
}
}
var RUN_BENCHMARKS = false;
//The tests...
(function(runner){
runner.addGroup("Basic Selectors").addTests(null, {
"*": function(){
//Universal selector
var results = [], nodes = document.getElementsByTagName("*"), index = 0, length = nodes.length, node;
//Collect all element nodes, excluding comments (IE)
for(; index < length; index++){
if((node = nodes[index]).tagName !== "!"){
results[results.length] = node;
}
}
this.assertEquivalent(select("*"), results, "Comment nodes should be ignored.");
},
"E": function(){
//Type selector
var results = [], index = 0, nodes = document.getElementsByTagName("li");
while((results[index] = nodes[index++])){}
results.length--;
// this.assertEquivalent(select("li"), results); //TODO
this.assertEqual(select("strong", getById("fixtures"))[0], getById("strong"));
this.assertEquivalent(select("nonexistent"), []);
},
"#id": function(){
//ID selector
this.assertEqual(select("#fixtures")[0], getById("fixtures"));
this.assertEquivalent(select("nonexistent"), []);
this.assertEqual(select("#troubleForm")[0], getById("troubleForm"));
},
".class": function(){
//Class selector
this.assertEquivalent(select(".first"), getById('p', 'link_1', 'item_1'));
this.assertEquivalent(select(".second"), []);
},
"E#id": function(){
this.assertEqual(select("strong#strong")[0], getById("strong"));
this.assertEquivalent(select("p#strong"), []);
},
"E.class": function(){
var secondLink = getById("link_2");
this.assertEquivalent(select('a.internal'), getById('link_1', 'link_2'));
this.assertEqual(select('a.internal.highlight')[0], secondLink);
this.assertEqual(select('a.highlight.internal')[0], secondLink);
this.assertEquivalent(select('a.highlight.internal.nonexistent'), []);
},
"#id.class": function(){
var secondLink = getById('link_2');
this.assertEqual(select('#link_2.internal')[0], secondLink);
this.assertEqual(select('.internal#link_2')[0], secondLink);
this.assertEqual(select('#link_2.internal.highlight')[0], secondLink);
this.assertEquivalent(select('#link_2.internal.nonexistent'), []);
},
"E#id.class": function(){
var secondLink = getById('link_2');
this.assertEqual(select('a#link_2.internal')[0], secondLink);
this.assertEqual(select('a.internal#link_2')[0], secondLink);
this.assertEqual(select('li#item_1.first')[0], getById("item_1"));
this.assertEquivalent(select('li#item_1.nonexistent'), []);
this.assertEquivalent(select('li#item_1.first.nonexistent'), []);
}
});
runner.addGroup("Attribute Selectors").addTests(null, {
"[foo]": function(){
this.assertEquivalent(select('[href]', document.body), select('a[href]', document.body));
this.assertEquivalent(select('[class~=internal]'), select('a[class~="internal"]'));
this.assertEquivalent(select('[id]'), select('*[id]'));
this.assertEquivalent(select('[type=radio]'), getById('checked_radio', 'unchecked_radio'));
this.assertEquivalent(select('[type=checkbox]'), select('*[type=checkbox]'));
this.assertEquivalent(select('[title]'), getById('with_title', 'commaParent'));
this.assertEquivalent(select('#troubleForm [type=radio]'), select('#troubleForm *[type=radio]'));
this.assertEquivalent(select('#troubleForm [type]'), select('#troubleForm *[type]'));
},
"E[foo]": function(){
this.assertEquivalent(select('h1[class]'), select('#fixtures h1'), "h1[class]");
this.assertEquivalent(select('h1[CLASS]'), select('#fixtures h1'), "h1[CLASS]");
this.assertEqual(select('li#item_3[class]')[0], getById('item_3'), "li#item_3[class]");
this.assertEquivalent(select('#troubleForm2 input[name="brackets[5][]"]'), getById('chk_1', 'chk_2'));
//Brackets in attribute value
this.assertEqual(select('#troubleForm2 input[name="brackets[5][]"]:checked')[0], getById('chk_1'));
//Space in attribute value
this.assertEqual(select('cite[title="hello world!"]')[0], getById('with_title'));
//Namespaced attributes
// this.assertEquivalent(select('[xml:lang]'), [document.documentElement, getById("item_3")]);
// this.assertEquivalent(select('*[xml:lang]'), [document.documentElement, getById("item_3")]);
},
'E[foo="bar"]': function(){
this.assertEquivalent(select('a[href="#"]'), getById('link_1', 'link_2', 'link_3'));
this.assertThrowsException(/Error/, function(){
select('a[href=#]');
});
this.assertEqual(select('#troubleForm2 input[name="brackets[5][]"][value="2"]')[0], getById('chk_2'));
},
'E[foo~="bar"]': function(){
this.assertEquivalent(select('a[class~="internal"]'), getById('link_1', 'link_2'), "a[class~=\"internal\"]");
this.assertEquivalent(select('a[class~=internal]'), getById('link_1', 'link_2'), "a[class~=internal]");
this.assertEqual(select('a[class~=external][href="#"]')[0], getById('link_3'), 'a[class~=external][href="#"]');
},/*
'E[foo|="en"]': function(){
this.assertEqual(select('*[xml:lang|="es"]')[0], getById('item_3'));
this.assertEqual(select('*[xml:lang|="ES"]')[0], getById('item_3'));
},*/
'E[foo^="bar"]': function(){
this.assertEquivalent(select('div[class^=bro]'), getById('father', 'uncle'), 'matching beginning of string');
this.assertEquivalent(select('#level1 *[id^="level2_"]'), getById('level2_1', 'level2_2', 'level2_3'));
this.assertEquivalent(select('#level1 *[id^=level2_]'), getById('level2_1', 'level2_2', 'level2_3'));
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[id^=level2_]');
}, 1000);
}, 500);
}
},
'E[foo$="bar"]': function(){
this.assertEquivalent(select('div[class$=men]'), getById('father', 'uncle'), 'matching end of string');
this.assertEquivalent(select('#level1 *[id$="_1"]'), getById('level2_1', 'level3_1'));
this.assertEquivalent(select('#level1 *[id$=_1]'), getById('level2_1', 'level3_1'));
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[id$=_1]');
}, 1000);
}, 500);
}
},
'E[foo*="bar"]': function(){
this.assertEquivalent(select('div[class*="ers m"]'), getById('father', 'uncle'), 'matching substring');
this.assertEquivalent(select('#level1 *[id*="2"]'), getById('level2_1', 'level3_2', 'level2_2', 'level2_3'));
this.assertThrowsException(/Error/, function(){
select('#level1 *[id*=2]');
});
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[id*=2]');
}, 1000);
}, 500);
}
},
// *** these should throw SYNTAX_ERR ***
'E[id=-1]': function(){
this.assertThrowsException(/Error/, function(){
select('#level1 *[id=-1]');
});
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[id=9]');
}, 1000);
}, 500);
}
},
'E[class=-45deg]': function(){
this.assertThrowsException(/Error/, function(){
select('#level1 *[class=-45deg]');
});
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[class=-45deg]');
}, 1000);
}, 500);
}
},
'E[class=8mm]': function(){
this.assertThrowsException(/Error/, function(){
select('#level1 *[class=8mm]');
});
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *[class=8mm]');
}, 1000);
}, 500);
}
}
});
runner.addGroup("Structural pseudo-classes").addTests(null, {
"E:first-child": function(){
this.assertEqual(select('#level1>*:first-child')[0], getById('level2_1'));
this.assertEquivalent(select('#level1 *:first-child'), getById('level2_1', 'level3_1', 'level_only_child'));
this.assertEquivalent(select('#level1>div:first-child'), []);
this.assertEquivalent(select('#level1 span:first-child'), getById('level2_1', 'level3_1'));
this.assertEquivalent(select('#level1:first-child'), []);
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *:first-child');
}, 1000);
}, 500);
}
},
"E:last-child": function(){
this.assertEqual(select('#level1>*:last-child')[0], getById('level2_3'));
this.assertEquivalent(select('#level1 *:last-child'), getById('level3_2', 'level_only_child', 'level2_3'));
this.assertEqual(select('#level1>div:last-child')[0], getById('level2_3'));
this.assertEqual(select('#level1 div:last-child')[0], getById('level2_3'));
this.assertEquivalent(select('#level1>span:last-child'), []);
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *:last-child');
}, 1000);
}, 500);
}
},
"E:nth-child(n)": function(){
this.assertEqual(select('#p *:nth-child(3)')[0], getById('link_2'));
this.assertEqual(select('#p a:nth-child(3)')[0], getById('link_2'), 'nth-child');
this.assertEquivalent(select('#list > li:nth-child(n+2)'), getById('item_2', 'item_3'));
this.assertEquivalent(select('#list > li:nth-child(-n+2)'), getById('item_1', 'item_2'));
},
"E:nth-of-type(n)": function(){
this.assertEqual(select('#p a:nth-of-type(2)')[0], getById('link_2'), 'nth-of-type');
this.assertEqual(select('#p a:nth-of-type(1)')[0], getById('link_1'), 'nth-of-type');
},
"E:nth-last-of-type(n)": function(){
this.assertEqual(select('#p a:nth-last-of-type(1)')[0], getById('link_2'), 'nth-last-of-type');
},
"E:first-of-type": function(){
this.assertEqual(select('#p a:first-of-type')[0], getById('link_1'), 'first-of-type');
},
"E:last-of-type": function(){
this.assertEqual(select('#p a:last-of-type')[0], getById('link_2'), 'last-of-type');
},
"E:only-child": function(){
this.assertEqual(select('#level1 *:only-child')[0], getById('level_only_child'));
//Shouldn't return anything
this.assertEquivalent(select('#level1>*:only-child'), []);
this.assertEquivalent(select('#level1:only-child'), []);
this.assertEquivalent(select('#level2_2 :only-child:not(:last-child)'), []);
this.assertEquivalent(select('#level2_2 :only-child:not(:first-child)'), []);
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 *:only-child');
}, 1000);
}, 500);
}
},
"E:empty": function(){
getById('level3_1').children = [];
if(document.createEvent){
this.assertEquivalent(select('#level1 *:empty'), getById('level3_1', 'level3_2', 'level2_3'), '#level1 *:empty');
this.assertEquivalent(select('#level_only_child:empty'), [], 'newlines count as content!');
}else{
this.assertEqual(select('#level3_1:empty')[0], getById('level3_1'), 'IE forced empty content!');
//this.skip("IE forced empty content!");
}
//Shouldn't return anything
this.assertEquivalent(select('span:empty > *'), []);
}
});
runner.addTests(null, {
"E:not(s)": function(){
//Negation pseudo-class
this.assertEquivalent(select('a:not([href="#"])'), []);
this.assertEquivalent(select('div.brothers:not(.brothers)'), []);
this.assertEquivalent(select('a[class~=external]:not([href="#"])'), [], 'a[class~=external][href!="#"]');
this.assertEqual(select('#p a:not(:first-of-type)')[0], getById('link_2'), 'first-of-type');
this.assertEqual(select('#p a:not(:last-of-type)')[0], getById('link_1'), 'last-of-type');
this.assertEqual(select('#p a:not(:nth-of-type(1))')[0], getById('link_2'), 'nth-of-type');
this.assertEqual(select('#p a:not(:nth-last-of-type(1))')[0], getById('link_1'), 'nth-last-of-type');
this.assertEqual(select('#p a:not([rel~=nofollow])')[0], getById('link_2'), 'attribute 1');
this.assertEqual(select('#p a:not([rel^=external])')[0], getById('link_2'), 'attribute 2');
this.assertEqual(select('#p a:not([rel$=nofollow])')[0], getById('link_2'), 'attribute 3');
this.assertEqual(select('#p a:not([rel$="nofollow"]) > em')[0], getById('em'), 'attribute 4');
this.assertEqual(select('#list li:not(#item_1):not(#item_3)')[0], getById('item_2'), 'adjacent :not clauses');
this.assertEqual(select('#grandfather > div:not(#uncle) #son')[0], getById('son'));
this.assertEqual(select('#p a:not([rel$="nofollow"]) em')[0], getById('em'), 'attribute 4 + all descendants');
this.assertEqual(select('#p a:not([rel$="nofollow"])>em')[0], getById('em'), 'attribute 4 (without whitespace)');
}
});
runner.addGroup("UI element states pseudo-classes").addTests(null, {
"E:disabled": function(){
this.assertEqual(select('#troubleForm > p > *:disabled')[0], getById('disabled_text_field'));
},
"E:checked": function(){
this.assertEquivalent(select('#troubleForm *:checked'), getById('checked_box', 'checked_radio'));
}
});
runner.addGroup("Combinators").addTests(null, {
"E F": function(){
//Descendant
this.assertEquivalent(select('#fixtures a *'), getById('em2', 'em', 'span'));
this.assertEqual(select('div#fixtures p')[0], getById("p"));
},
"E + F": function(){
//Adjacent sibling
this.assertEqual(select('div.brothers + div.brothers')[0], getById("uncle"));
this.assertEqual(select('div.brothers + div')[0], getById('uncle'));
this.assertEqual(select('#level2_1+span')[0], getById('level2_2'));
this.assertEqual(select('#level2_1 + span')[0], getById('level2_2'));
this.assertEqual(select('#level2_1 + *')[0], getById('level2_2'));
this.assertEquivalent(select('#level2_2 + span'), []);
this.assertEqual(select('#level3_1 + span')[0], getById('level3_2'));
this.assertEqual(select('#level3_1 + *')[0], getById('level3_2'));
this.assertEquivalent(select('#level3_2 + *'), []);
this.assertEquivalent(select('#level3_1 + em'), []);
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level3_1 + span');
}, 1000);
}, 500);
}
},
"E > F": function(){
//Child
this.assertEquivalent(select('p.first > a'), getById('link_1', 'link_2'));
this.assertEquivalent(select('div#grandfather > div'), getById('father', 'uncle'));
this.assertEquivalent(select('#level1>span'), getById('level2_1', 'level2_2'));
this.assertEquivalent(select('#level1 > span'), getById('level2_1', 'level2_2'));
this.assertEquivalent(select('#level2_1 > *'), getById('level3_1', 'level3_2'));
this.assertEquivalent(select('div > #nonexistent'), []);
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level1 > span');
}, 1000);
}, 500);
}
},
"E ~ F": function(){
//General sibling
this.assertEqual(select('h1 ~ ul')[0], getById('list'));
this.assertEquivalent(select('#level2_2 ~ span'), []);
this.assertEquivalent(select('#level3_2 ~ *'), []);
this.assertEquivalent(select('#level3_1 ~ em'), []);
this.assertEquivalent(select('div ~ #level3_2'), []);
this.assertEquivalent(select('div ~ #level2_3'), []);
this.assertEqual(select('#level2_1 ~ span')[0], getById('level2_2'));
this.assertEquivalent(select('#level2_1 ~ *'), getById('level2_2', 'level2_3'));
this.assertEqual(select('#level3_1 ~ #level3_2')[0], getById('level3_2'));
this.assertEqual(select('span ~ #level3_2')[0], getById('level3_2'));
if(RUN_BENCHMARKS){
this.wait(function(){
this.benchmark(function(){
select('#level2_1 ~ span');
}, 1000);
}, 500);
}
}
});
runner.addTests(null, {
"NW.Dom.match": function(){
var element = getById('dupL1');
//Assertions
this.assert(match(element, 'span'));
this.assert(match(element, "span#dupL1"));
this.assert(match(element, "div > span"), "child combinator");
this.assert(match(element, "#dupContainer span"), "descendant combinator");
this.assert(match(element, "#dupL1"), "ID only");
this.assert(match(element, "span.span_foo"), "class name 1");
this.assert(match(element, "span.span_bar"), "class name 2");
this.assert(match(element, "span:first-child"), "first-child pseudoclass");
//Refutations
this.refute(match(element, "span.span_wtf"), "bogus class name");
this.refute(match(element, "#dupL2"), "different ID");
this.refute(match(element, "div"), "different tag name");
this.refute(match(element, "span span"), "different ancestry");
this.refute(match(element, "span > span"), "different parent");
this.refute(match(element, "span:nth-child(5)"), "different pseudoclass");
//Misc.
this.refute(match(getById('link_2'), 'a[rel^=external]'));
this.assert(match(getById('link_1'), 'a[rel^=external]'));
this.assert(match(getById('link_1'), 'a[rel^="external"]'));
this.assert(match(getById('link_1'), "a[rel^='external']"));
},
"Equivalent Selectors": function(){
this.assertEquivalent(select('div.brothers'), select('div[class~=brothers]'));
this.assertEquivalent(select('div.brothers'), select('div[class~=brothers].brothers'));
this.assertEquivalent(select('div:not(.brothers)'), select('div:not([class~=brothers])'));
this.assertEquivalent(select('li ~ li'), select('li:not(:first-child)'));
this.assertEquivalent(select('ul > li'), select('ul > li:nth-child(n)'));
this.assertEquivalent(select('ul > li:nth-child(even)'), select('ul > li:nth-child(2n)'));
this.assertEquivalent(select('ul > li:nth-child(odd)'), select('ul > li:nth-child(2n+1)'));
this.assertEquivalent(select('ul > li:first-child'), select('ul > li:nth-child(1)'));
this.assertEquivalent(select('ul > li:last-child'), select('ul > li:nth-last-child(1)'));
/* Opera 10 does not accept values > 128 as a parameter to :nth-child
See <http://operawiki.info/ArtificialLimits> */
this.assertEquivalent(select('ul > li:nth-child(n-128)'), select('ul > li'));
this.assertEquivalent(select('ul>li'), select('ul > li'));
this.assertEquivalent(select('#p a:not([rel$="nofollow"])>em'), select('#p a:not([rel$="nofollow"]) > em'));
},
"Multiple Selectors": function(){
//The next two assertions should return document-ordered lists of matching elements --Diego Perini
// this.assertEquivalent(select('#list, .first,*[xml:lang="es-us"] , #troubleForm'), getById('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm'));
// this.assertEquivalent(select('#list, .first, *[xml:lang="es-us"], #troubleForm'), getById('p', 'link_1', 'list', 'item_1', 'item_3', 'troubleForm'));
this.assertEquivalent(select('form[title*="commas,"], input[value="#commaOne,#commaTwo"]'), getById('commaParent', 'commaChild'));
this.assertEquivalent(select('form[title*="commas,"], input[value="#commaOne,#commaTwo"]'), getById('commaParent', 'commaChild'));
}
});
}(runner));

View File

@ -1,92 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>NWMatcher Tests</title>
<link rel="stylesheet" type="text/css" href="assets/style.css" media="screen" />
<script type="text/javascript" src="../../src/nwmatcher.js"></script>
<script type="text/javascript" src="scotch.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<div id="container">
<div id="testlog" class="log"></div>
<!-- Test elements -->
<div id="fixtures" style="display: none;">
<h1 class="title">Some title <span>here</span></h1>
<p id="p" class="first summary">
<strong id="strong">This</strong> is a short blurb
<a id="link_1" class="first internal" rel="external nofollow" href="#">with a <em id="em2">link</em></a> or
<a id="link_2" class="internal highlight" href="#"><em id="em">two</em></a>.
Or <cite id="with_title" title="hello world!">a citation</cite>.
</p>
<ul id="list">
<li id="item_1" class="first"><a id="link_3" href="#" class="external"><span id="span">Another link</span></a></li>
<li id="item_2">Some text</li>
<li id="item_3" xml:lang="es-us" class="">Otra cosa</li>
</ul>
<!-- This form has a field with the name "id"; its "ID" property won't be "troubleForm" -->
<form id="troubleForm" action="">
<p>
<input type="hidden" name="id" id="hidden" />
<input type="text" name="disabled_text_field" id="disabled_text_field" disabled="disabled" />
<input type="text" name="enabled_text_field" id="enabled_text_field" />
<input type="checkbox" name="checkboxes" id="checked_box" checked="checked" value="Checked" />
<input type="checkbox" name="checkboxes" id="unchecked_box" value="Unchecked"/>
<input type="radio" name="radiobuttons" id="checked_radio" checked="checked" value="Checked" />
<input type="radio" name="radiobuttons" id="unchecked_radio" value="Unchecked" />
</p>
</form>
<form id="troubleForm2" action="">
<p>
<input type="checkbox" name="brackets[5][]" id="chk_1" checked="checked" value="1" />
<input type="checkbox" name="brackets[5][]" id="chk_2" value="2" />
</p>
</form>
<div id="level1">
<span id="level2_1">
<span id="level3_1"></span>
<!-- This comment should be ignored by the adjacent selector -->
<span id="level3_2"></span>
</span>
<span id="level2_2">
<em id="level_only_child">
</em>
</span>
<div id="level2_3"></div>
</div> <!-- #level1 -->
<div id="dupContainer">
<span id="dupL1" class="span_foo span_bar">
<span id="dupL2">
<span id="dupL3">
<span id="dupL4">
<span id="dupL5"></span>
</span>
</span>
</span>
</span>
</div> <!-- #dupContainer -->
<div id="grandfather"> grandfather
<div id="father" class="brothers men"> father
<div id="son"> son </div>
</div>
<div id="uncle" class="brothers men"> uncle </div>
</div>
<form id="commaParent" title="commas,are,good" action="">
<p>
<input type="hidden" id="commaChild" name="foo" value="#commaOne,#commaTwo" />
<input type="hidden" id="commaTwo" name="foo2" value="oops" />
</p>
</form>
<div id="counted_container"><div class="is_counted"></div></div>
</div>
</div>
</body>
</html>

View File

@ -1,132 +0,0 @@
<!DOCTYPE HTML>
<html lang="en-us">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Qwery tests</title>
<style type="text/css">
#fixtures {
position: absolute;
top: -9999px;
}
</style>
<link rel="stylesheet" href="../node_modules/sink-test/src/sink.css" type="text/css">
<script src="../node_modules/sink-test/src/sink.js"></script>
<script src="../src/qwery.js"></script>
<script src="../pseudos/qwery-pseudos.js"></script>
<script type="text/javascript">
var Q = qwery
</script>
</head>
<body>
<h1>Qwery Tests</h1>
<div id="fixtures">
<ol id="list">
<li>hello</li>
<li>world</li>
<ol>
<li>world</li>
<li id="attr-child-boosh" attr="boosh">hello</li>
</ol>
<li>humans</li>
</ol>
<div id="spaced-tokens">
<p><em><a href="#"></a></em></p>
<p></p>
</div>
<div id="pseudos">
<div class="odd pseudos pseudo-1"></div>
<div class="even pseudos pseudo-2"></div>
<div class="odd"></div>
<div class="even"></div>
<a class="odd"></a>
<div class="even"></div>
<div class="odd"></div>
</div>
<div foo="bar"></div>
<div class="a"></div>
<div class="class-with-dashes"></div>
<div id="boosh">
<!-- comment -->
<!-- comment -->
<div class="a b">
<div class="d e" test="fg" id="booshTest"></div>
<!-- comment -->
<em nopass="copyrighters" rel="copyright booshrs" test="f g"></em>
<span class="h i a"></span>
</div>
<!-- comment -->
</div>
<div id="lonelyBoosh"></div>
<div id="attr-test1" -data-attr></div>
<div id="attr-test2" -data-attr></div>
<div id="attr-test3" class="found you" -data-attr title="whatup duders"></div>
<div id="attributes">
<div test="one" unique-test="baz" id="attr-test-1"></div>
<div test="two-foo" id="attr-test-2"></div>
<div test=" three " id="attr-test-3"></div>
<a href="#aname" id="attr-test-4">aname</a>
</div>
<div class="idless">
<div class="tokens" title="one" id="token-one"></div>
<div class="tokens" title="one two" id="token-two"></div>
<div class="tokens" title="one two three #%" id="token-three">
<a href="foo" id="token-four">
<div id="token-five"></div>
</a>
</div>
</div>
<div id="order-matters" class="order-matters">
<p class="order-matters"></p>
<a class="order-matters">
<em class="order-matters"></em><b class="order-matters"></b>
</a>
</div>
<div id="direct-descend" class="oogabooga">
<div></div>
<div class="direct-descend">
<span></span>
<div class="direct-descend">
<div class="lvl2" id="toodeep"><span></span></div>
</div>
<div class="direct-descend"><span></span></div>
<div class="lvl2" id="l2">
<span></span>
<div class="direct-descend"><span></span></div>
</div>
<div class="lvl2" id="l3"></div>
</div>
<div class="ignoreme"></div>
<div class="direct-descend">
<div class="direct-descend"></div>
<div class="lvl2" id="l4"></div>
</div>
<div></div>
</div>
<div id="sibling-selector"></div>
<div class="sibling-selector" id="sib1">
<div class="sibling-selector"></div>
<div class="sibling-selector"></div>
</div>
<div class="sibling-selector" id="sib2">
<div class="sibling-selector">
<div class="sibling-selector"></div>
</div>
</div>
<div class="parent">
<h1 class="sibling oldest"></h1>
<h2 class="sibling older"></h2>
<h3 class="sibling middle"></h3>
<h4 class="sibling younger"></h4>
<h5 class="sibling youngest"></h5>
</div>
<form>
<button></button>
<input type="text">
<input type="hidden">
</form>
</div>
<ol id="tests"></ol>
<iframe id="frame" style="width: 0; height: 0; margin-left: -1000px;"></iframe>
<script src="tests.js"></script>
</body>
</html>

View File

@ -1,549 +0,0 @@
"use strict";
var expect = require("expect.js"),
DomUtils = require("htmlparser2").DomUtils,
helper = require("../tools/helper.js"),
path = require("path"),
document = helper.getDocument(path.join(__dirname, "index.html")),
CSSselect = helper.CSSselect;
var location = {hash: ""};
CSSselect.pseudos.target = function(elem){
return elem.attribs && elem.attribs.id === location.hash.substr(1);
};
//---
/*
The following is taken from https://github.com/ded/qwery/blob/master/tests/tests.js
*/
CSSselect.pseudos.humanoid = function(e) { return CSSselect.is(e, 'li:contains(human)') || CSSselect.is(e, 'ol:contains(human)'); };
var frag = helper.getDOM(
'<div class="d i v">' +
'<p id="oooo"><em></em><em id="emem"></em></p>' +
'</div>' +
'<p id="sep">' +
'<div class="a"><span></span></div>' +
'</p>'
);
var doc = helper.getDOM(
'<div id="hsoob">' +
'<div class="a b">' +
'<div class="d e sib" test="fg" id="booshTest"><p><span id="spanny"></span></p></div>' +
'<em nopass="copyrighters" rel="copyright booshrs" test="f g" class="sib"></em>' +
'<span class="h i a sib"></span>' +
'</div>' +
'<p class="odd"></p>' +
'</div>' +
'<div id="lonelyHsoob"></div>'
);
var el = DomUtils.getElementById('attr-child-boosh', document);
var pseudos = DomUtils.getElementById('pseudos', document).children.filter(DomUtils.isTag);
module.exports = {
'Contexts': {
'should be able to pass optional context': function () {
expect(CSSselect('.a', document)).to.have.length(3); //no context found 3 elements (.a)
expect(CSSselect('.a', CSSselect('#boosh', document))).to.have.length(2); //context found 2 elements (#boosh .a)
},
/*
'should be able to pass string as context': function() {
expect(CSSselect('.a', '#boosh')).to.have.length(2); //context found 2 elements(.a, #boosh)
expect(CSSselect('.a', '.a')).to.be.empty(); //context found 0 elements(.a, .a)
expect(CSSselect('.a', '.b')).to.have.length(1); //context found 1 elements(.a, .b)
expect(CSSselect('.a', '#boosh .b')).to.have.length(1); //context found 1 elements(.a, #boosh .b)
expect(CSSselect('.b', '#boosh .b')).to.be.empty(); //context found 0 elements(.b, #boosh .b)
},
*/
/*
'should be able to pass qwery result as context': function() {
expect(CSSselect('.a', CSSselect('#boosh', document))).to.have.length(2); //context found 2 elements(.a, #boosh)
expect(CSSselect('.a', CSSselect('.a', document))).to.be.empty(); //context found 0 elements(.a, .a)
expect(CSSselect('.a', CSSselect('.b', document))).to.have.length(1); //context found 1 elements(.a, .b)
expect(CSSselect('.a', CSSselect('#boosh .b', document))).to.have.length(1); //context found 1 elements(.a, #boosh .b)
expect(CSSselect('.b', CSSselect('#boosh .b', document))).to.be.empty(); //context found 0 elements(.b, #boosh .b)
},
*/
'should not return duplicates from combinators': function () {
expect(CSSselect('#boosh,#boosh', document)).to.have.length(1); //two booshes dont make a thing go right
expect(CSSselect('#boosh,.apples,#boosh', document)).to.have.length(1); //two booshes and an apple dont make a thing go right
},
'byId sub-queries within context': function() {
expect(CSSselect('#booshTest', CSSselect('#boosh', document))).to.have.length(1); //found "#id #id"
expect(CSSselect('.a.b #booshTest', CSSselect('#boosh', document))).to.have.length(1); //found ".class.class #id"
expect(CSSselect('.a>#booshTest', CSSselect('#boosh', document))).to.have.length(1); //found ".class>#id"
expect(CSSselect('>.a>#booshTest', CSSselect('#boosh', document))).to.have.length(1); //found ">.class>#id"
expect(CSSselect('#boosh', CSSselect('#booshTest', document)).length).to.not.be.ok(); //shouldn't find #boosh (ancestor) within #booshTest (descendent)
expect(CSSselect('#boosh', CSSselect('#lonelyBoosh', document)).length).to.not.be.ok(); //shouldn't find #boosh within #lonelyBoosh (unrelated)
}
},
'CSS 1': {
'get element by id': function () {
var result = CSSselect('#boosh', document);
expect(result[0]).to.be.ok(); //found element with id=boosh
expect(CSSselect('h1', document)[0]).to.be.ok(); //found 1 h1
},
'byId sub-queries': function() {
expect(CSSselect('#boosh #booshTest', document)).to.have.length(1); //found "#id #id"
expect(CSSselect('.a.b #booshTest', document)).to.have.length(1); //found ".class.class #id"
expect(CSSselect('#boosh>.a>#booshTest', document)).to.have.length(1); //found "#id>.class>#id"
expect(CSSselect('.a>#booshTest', document)).to.have.length(1); //found ".class>#id"
},
'get elements by class': function () {
expect(CSSselect('#boosh .a', document)).to.have.length(2); //found two elements
expect(CSSselect('#boosh div.a', document)[0]).to.be.ok(); //found one element
expect(CSSselect('#boosh div', document)).to.have.length(2); //found two {div} elements
expect(CSSselect('#boosh span', document)[0]).to.be.ok(); //found one {span} element
expect(CSSselect('#boosh div div', document)[0]).to.be.ok(); //found a single div
expect(CSSselect('a.odd', document)).to.have.length(1); //found single a
},
'combos': function () {
expect(CSSselect('#boosh div,#boosh span', document)).to.have.length(3); //found 2 divs and 1 span
},
'class with dashes': function() {
expect(CSSselect('.class-with-dashes', document)).to.have.length(1); //found something
},
'should ignore comment nodes': function() {
expect(CSSselect('#boosh *', document)).to.have.length(4); //found only 4 elements under #boosh
},
'deep messy relationships': function() {
// these are mostly characterised by a combination of tight relationships and loose relationships
// on the right side of the query it's easy to find matches but they tighten up quickly as you
// go to the left
// they are useful for making sure the dom crawler doesn't stop short or over-extend as it works
// up the tree the crawl needs to be comprehensive
expect(CSSselect('div#fixtures > div a', document)).to.have.length(5); //found four results for "div#fixtures > div a"
expect(CSSselect('.direct-descend > .direct-descend .lvl2', document)).to.have.length(1); //found one result for ".direct-descend > .direct-descend .lvl2"
expect(CSSselect('.direct-descend > .direct-descend div', document)).to.have.length(1); //found one result for ".direct-descend > .direct-descend div"
expect(CSSselect('.direct-descend > .direct-descend div', document)).to.have.length(1); //found one result for ".direct-descend > .direct-descend div"
expect(CSSselect('div#fixtures div ~ a div', document)).to.be.empty(); //found no results for odd query
expect(CSSselect('.direct-descend > .direct-descend > .direct-descend ~ .lvl2', document)).to.be.empty(); //found no results for another odd query
}
},
'CSS 2': {
'get elements by attribute': function () {
var wanted = CSSselect('#boosh div[test]', document)[0];
var expected = DomUtils.getElementById('booshTest', document);
expect(wanted).to.be(expected); //found attribute
expect(CSSselect('#boosh div[test=fg]', document)[0]).to.be(expected); //found attribute with value
expect(CSSselect('em[rel~="copyright"]', document)).to.have.length(1); //found em[rel~="copyright"]
expect(CSSselect('em[nopass~="copyright"]', document)).to.be.empty(); //found em[nopass~="copyright"]
},
'should not throw error by attribute selector': function () {
expect(CSSselect('[foo^="bar"]', document)).to.have.length(1); //found 1 element
},
'crazy town': function () {
var el = DomUtils.getElementById('attr-test3', document);
expect(CSSselect('div#attr-test3.found.you[title="whatup duders"]', document)[0]).to.be(el); //found the right element
}
},
'attribute selectors': {
/* CSS 2 SPEC */
'[attr]': function () {
var expected = DomUtils.getElementById('attr-test-1', document);
expect(CSSselect('#attributes div[unique-test]', document)[0]).to.be(expected); //found attribute with [attr]
},
'[attr=val]': function () {
var expected = DomUtils.getElementById('attr-test-2', document);
expect(CSSselect('#attributes div[test="two-foo"]', document)[0]).to.be(expected); //found attribute with =
expect(CSSselect("#attributes div[test='two-foo']", document)[0]).to.be(expected); //found attribute with =
expect(CSSselect('#attributes div[test=two-foo]', document)[0]).to.be(expected); //found attribute with =
},
'[attr~=val]': function () {
var expected = DomUtils.getElementById('attr-test-3', document);
expect(CSSselect('#attributes div[test~=three]', document)[0]).to.be(expected); //found attribute with ~=
},
'[attr|=val]': function () {
var expected = DomUtils.getElementById('attr-test-2', document);
expect(CSSselect('#attributes div[test|="two-foo"]', document)[0]).to.be(expected); //found attribute with |=
expect(CSSselect('#attributes div[test|=two]', document)[0]).to.be(expected); //found attribute with |=
},
'[href=#x] special case': function () {
var expected = DomUtils.getElementById('attr-test-4', document);
expect(CSSselect('#attributes a[href="#aname"]', document)[0]).to.be(expected); //found attribute with href=#x
},
/* CSS 3 SPEC */
'[attr^=val]': function () {
var expected = DomUtils.getElementById('attr-test-2', document);
expect(CSSselect('#attributes div[test^=two]', document)[0]).to.be(expected); //found attribute with ^=
},
'[attr$=val]': function () {
var expected = DomUtils.getElementById('attr-test-2', document);
expect(CSSselect('#attributes div[test$=foo]', document)[0]).to.be(expected); //found attribute with $=
},
'[attr*=val]': function () {
var expected = DomUtils.getElementById('attr-test-3', document);
expect(CSSselect('#attributes div[test*=hree]', document)[0]).to.be(expected); //found attribute with *=
},
'direct descendants': function () {
expect(CSSselect('#direct-descend > .direct-descend', document)).to.have.length(2); //found two direct descendents
expect(CSSselect('#direct-descend > .direct-descend > .lvl2', document)).to.have.length(3); //found three second-level direct descendents
},
'sibling elements': function () {
expect(CSSselect('#sibling-selector ~ .sibling-selector', document)).to.have.length(2); //found two siblings
expect(CSSselect('#sibling-selector ~ div.sibling-selector', document)).to.have.length(2); //found two siblings
expect(CSSselect('#sibling-selector + div.sibling-selector', document)).to.have.length(1); //found one sibling
expect(CSSselect('#sibling-selector + .sibling-selector', document)).to.have.length(1); //found one sibling
expect(CSSselect('.parent .oldest ~ .sibling', document)).to.have.length(4); //found four younger siblings
expect(CSSselect('.parent .middle ~ .sibling', document)).to.have.length(2); //found two younger siblings
expect(CSSselect('.parent .middle ~ h4', document)).to.have.length(1); //found next sibling by tag
expect(CSSselect('.parent .middle ~ h4.younger', document)).to.have.length(1); //found next sibling by tag and class
expect(CSSselect('.parent .middle ~ h3', document)).to.be.empty(); //an element can't be its own sibling
expect(CSSselect('.parent .middle ~ h2', document)).to.be.empty(); //didn't find an older sibling
expect(CSSselect('.parent .youngest ~ .sibling', document)).to.be.empty(); //found no younger siblings
expect(CSSselect('.parent .oldest + .sibling', document)).to.have.length(1); //found next sibling
expect(CSSselect('.parent .middle + .sibling', document)).to.have.length(1); //found next sibling
expect(CSSselect('.parent .middle + h4', document)).to.have.length(1); //found next sibling by tag
expect(CSSselect('.parent .middle + h3', document)).to.be.empty(); //an element can't be its own sibling
expect(CSSselect('.parent .middle + h2', document)).to.be.empty(); //didn't find an older sibling
expect(CSSselect('.parent .youngest + .sibling', document)).to.be.empty(); //found no younger siblings
}
},
/*
'Uniq': {
'duplicates arent found in arrays': function () {
expect(CSSselect.uniq(['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e'])).to.have.length(5); //result should be a, b, c, d, e
expect(CSSselect.uniq(['a', 'b', 'c', 'c', 'c'])).to.have.length(3); //result should be a, b, c
}
},
*/
'element-context queries': {
/*
'relationship-first queries': function() {
expect(CSSselect('> .direct-descend', CSSselect('#direct-descend', document))).to.have.length(2); //found two direct descendents using > first
expect(CSSselect('~ .sibling-selector', CSSselect('#sibling-selector', document))).to.have.length(2); //found two siblings with ~ first
expect(CSSselect('+ .sibling-selector', CSSselect('#sibling-selector', document))).to.have.length(1); //found one sibling with + first
expect(CSSselect('> .tokens a', CSSselect('.idless', document)[0])).to.have.length(1); //found one sibling from a root with no id
},
*/
// should be able to query on an element that hasn't been inserted into the dom
'detached fragments': function() {
expect(CSSselect('.a span', frag)).to.have.length(1); //should find child elements of fragment
//expect(CSSselect('> div p em', frag)).to.have.length(2); //should find child elements of fragment, relationship first
},
'byId sub-queries within detached fragment': function () {
expect(CSSselect('#emem', frag)).to.have.length(1); //found "#id" in fragment
expect(CSSselect('.d.i #emem', frag)).to.have.length(1); //found ".class.class #id" in fragment
expect(CSSselect('.d #oooo #emem', frag)).to.have.length(1); //found ".class #id #id" in fragment
//expect(CSSselect('> div #oooo', frag)).to.have.length(1); //found "> .class #id" in fragment
expect(CSSselect('#oooo', CSSselect('#emem', frag)).length).to.not.be.ok(); //shouldn't find #oooo (ancestor) within #emem (descendent)
expect(CSSselect('#sep', CSSselect('#emem', frag)).length).to.not.be.ok(); //shouldn't find #sep within #emem (unrelated)
},
/*
'exclude self in match': function() {
expect(CSSselect('.order-matters', CSSselect('#order-matters', document))).to.have.length(4); //should not include self in element-context queries
},
*/
// because form's have .length
'forms can be used as contexts': function() {
expect(CSSselect('*', CSSselect('form', document)[0])).to.have.length(3); //found 3 elements under &lt;form&gt;
}
},
'tokenizer': {
'should not get weird tokens': function () {
expect(CSSselect('div .tokens[title="one"]', document)[0]).to.be(DomUtils.getElementById('token-one', document)); //found div .tokens[title="one"]
expect(CSSselect('div .tokens[title="one two"]', document)[0]).to.be(DomUtils.getElementById('token-two', document)); //found div .tokens[title="one two"]
expect(CSSselect('div .tokens[title="one two three #%"]', document)[0]).to.be(DomUtils.getElementById('token-three', document)); //found div .tokens[title="one two three #%"]
expect(CSSselect("div .tokens[title='one two three #%'] a", document)[0]).to.be(DomUtils.getElementById('token-four', document)); //found div .tokens[title=\'one two three #%\'] a
expect(CSSselect('div .tokens[title="one two three #%"] a[href$=foo] div', document)[0]).to.be(DomUtils.getElementById('token-five', document)); //found div .tokens[title="one two three #%"] a[href=foo] div
}
},
'interesting syntaxes': {
'should parse bad selectors': function () {
expect(CSSselect('#spaced-tokens p em a', document).length).to.be.ok(); //found element with funny tokens
}
},
'order matters': {
// <div id="order-matters">
// <p class="order-matters"></p>
// <a class="order-matters">
// <em class="order-matters"></em><b class="order-matters"></b>
// </a>
// </div>
'the order of elements return matters': function () {
function tag(el) {
return el.name.toLowerCase();
}
var els = CSSselect('#order-matters .order-matters', document);
expect(tag(els[0])).to.be('p'); //first element matched is a {p} tag
expect(tag(els[1])).to.be('a'); //first element matched is a {a} tag
expect(tag(els[2])).to.be('em'); //first element matched is a {em} tag
expect(tag(els[3])).to.be('b'); //first element matched is a {b} tag
}
},
'pseudo-selectors': {
':contains': function() {
expect(CSSselect('li:contains(humans)', document)).to.have.length(1); //found by "element:contains(text)"
expect(CSSselect(':contains(humans)', document)).to.have.length(5); //found by ":contains(text)", including all ancestors
// * is an important case, can cause weird errors
expect(CSSselect('*:contains(humans)', document)).to.have.length(5); //found by "*:contains(text)", including all ancestors
expect(CSSselect('ol:contains(humans)', document)).to.have.length(1); //found by "ancestor:contains(text)"
},
':not': function() {
expect(CSSselect('.odd:not(div)', document)).to.have.length(1); //found one .odd :not an &lt;a&gt;
},
':first-child': function () {
expect(CSSselect('#pseudos div:first-child', document)[0]).to.be(pseudos[0]); //found first child
expect(CSSselect('#pseudos div:first-child', document)).to.have.length(1); //found only 1
},
':last-child': function () {
var all = DomUtils.getElementsByTagName('div', pseudos);
expect(CSSselect('#pseudos div:last-child', document)[0]).to.be(all[all.length - 1]); //found last child
expect(CSSselect('#pseudos div:last-child', document)).to.have.length(1); //found only 1
},
'ol > li[attr="boosh"]:last-child': function () {
var expected = DomUtils.getElementById('attr-child-boosh', document);
expect(CSSselect('ol > li[attr="boosh"]:last-child', document)).to.have.length(1); //only 1 element found
expect(CSSselect('ol > li[attr="boosh"]:last-child', document)[0]).to.be(expected); //found correct element
},
':nth-child(odd|even|x)': function () {
var second = DomUtils.getElementsByTagName('div', pseudos)[1];
expect(CSSselect('#pseudos :nth-child(odd)', document)).to.have.length(4); //found 4 odd elements
expect(CSSselect('#pseudos div:nth-child(odd)', document)).to.have.length(3); //found 3 odd elements with div tag
expect(CSSselect('#pseudos div:nth-child(even)', document)).to.have.length(3); //found 3 even elements with div tag
expect(CSSselect('#pseudos div:nth-child(2)', document)[0]).to.be(second); //found 2nd nth-child of pseudos
},
':nth-child(expr)': function () {
var fifth = DomUtils.getElementsByTagName('a', pseudos)[0];
var sixth = DomUtils.getElementsByTagName('div', pseudos)[4];
expect(CSSselect('#pseudos :nth-child(3n+1)', document)).to.have.length(3); //found 3 elements
expect(CSSselect('#pseudos :nth-child(+3n-2)', document)).to.have.length(3); //found 3 elements'
expect(CSSselect('#pseudos :nth-child(-n+6)', document)).to.have.length(6); //found 6 elements
expect(CSSselect('#pseudos :nth-child(-n+5)', document)).to.have.length(5); //found 5 elements
expect(CSSselect('#pseudos :nth-child(3n+2)', document)[1]).to.be(fifth); //second :nth-child(3n+2) is the fifth child
expect(CSSselect('#pseudos :nth-child(3n)', document)[1]).to.be(sixth); //second :nth-child(3n) is the sixth child
},
':nth-last-child(odd|even|x)': function () {
var second = DomUtils.getElementsByTagName('div', pseudos)[1];
expect(CSSselect('#pseudos :nth-last-child(odd)', document)).to.have.length(4); //found 4 odd elements
expect(CSSselect('#pseudos div:nth-last-child(odd)', document)).to.have.length(3); //found 3 odd elements with div tag
expect(CSSselect('#pseudos div:nth-last-child(even)', document)).to.have.length(3); //found 3 even elements with div tag
expect(CSSselect('#pseudos div:nth-last-child(6)', document)[0]).to.be(second); //6th nth-last-child should be 2nd of 7 elements
},
':nth-last-child(expr)': function () {
var third = DomUtils.getElementsByTagName('div', pseudos)[2];
expect(CSSselect('#pseudos :nth-last-child(3n+1)', document)).to.have.length(3); //found 3 elements
expect(CSSselect('#pseudos :nth-last-child(3n-2)', document)).to.have.length(3); //found 3 elements
expect(CSSselect('#pseudos :nth-last-child(-n+6)', document)).to.have.length(6); //found 6 elements
expect(CSSselect('#pseudos :nth-last-child(-n+5)', document)).to.have.length(5); //found 5 elements
expect(CSSselect('#pseudos :nth-last-child(3n+2)', document)[0]).to.be(third); //first :nth-last-child(3n+2) is the third child
},
':nth-of-type(expr)': function () {
var a = DomUtils.getElementsByTagName('a', pseudos)[0];
expect(CSSselect('#pseudos div:nth-of-type(3n+1)', document)).to.have.length(2); //found 2 div elements
expect(CSSselect('#pseudos a:nth-of-type(3n+1)', document)).to.have.length(1); //found 1 a element
expect(CSSselect('#pseudos a:nth-of-type(3n+1)', document)[0]).to.be(a); //found the right a element
expect(CSSselect('#pseudos a:nth-of-type(3n)', document)).to.be.empty(); //no matches for every third a
expect(CSSselect('#pseudos a:nth-of-type(odd)', document)).to.have.length(1); //found the odd a
expect(CSSselect('#pseudos a:nth-of-type(1)', document)).to.have.length(1); //found the first a
},
':nth-last-of-type(expr)': function () {
var second = DomUtils.getElementsByTagName('div', pseudos)[1];
expect(CSSselect('#pseudos div:nth-last-of-type(3n+1)', document)).to.have.length(2); //found 2 div elements
expect(CSSselect('#pseudos a:nth-last-of-type(3n+1)', document)).to.have.length(1); //found 1 a element
expect(CSSselect('#pseudos div:nth-last-of-type(5)', document)[0]).to.be(second); //5th nth-last-of-type should be 2nd of 7 elements
},
':first-of-type': function () {
expect(CSSselect('#pseudos a:first-of-type', document)[0]).to.be(DomUtils.getElementsByTagName('a', pseudos)[0]); //found first a element
expect(CSSselect('#pseudos a:first-of-type', document)).to.have.length(1); //found only 1
},
':last-of-type': function () {
var all = DomUtils.getElementsByTagName('div', pseudos);
expect(CSSselect('#pseudos div:last-of-type', document)[0]).to.be(all[all.length - 1]); //found last div element
expect(CSSselect('#pseudos div:last-of-type', document)).to.have.length(1); //found only 1
},
':only-of-type': function () {
expect(CSSselect('#pseudos a:only-of-type', document)[0]).to.be(DomUtils.getElementsByTagName('a', pseudos)[0]); //found the only a element
expect(CSSselect('#pseudos a:first-of-type', document)).to.have.length(1); //found only 1
},
':target': function () {
location.hash = '';
expect(CSSselect('#pseudos:target', document)).to.be.empty(); //#pseudos is not the target
location.hash = '#pseudos';
expect(CSSselect('#pseudos:target', document)).to.have.length(1); //now #pseudos is the target
location.hash = '';
},
'custom pseudos': function() {
// :humanoid implemented just for testing purposes
expect(CSSselect(':humanoid', document)).to.have.length(2); //selected using custom pseudo
}
},
/*
'argument types': {
'should be able to pass in nodes as arguments': function () {
var el = DomUtils.getElementById('boosh', document);
expect(CSSselect(el)[0]).to.be(el); //CSSselect(el)[0] == el
expect(CSSselect(el, 'body')[0]).to.be(el); //CSSselect(el, 'body')[0] == el
expect(CSSselect(el, document)[0]).to.be(el); //CSSselect(el, document)[0] == el
expect(CSSselect(window)[0]).to.be(window); //CSSselect(window)[0] == window
expect(CSSselect(document)[0]).to.be(document); //CSSselect(document)[0] == document
},
'should be able to pass in an array of results as arguments': function () {
var el = DomUtils.getElementById('boosh', document);
var result = CSSselect([CSSselect('#boosh', document), CSSselect(document), CSSselect(window)]);
expect(result).to.have.length(3); //3 elements in the combined set
expect(result[0]).to.be(el); //result[0] == el
expect(result[1]).to.be(document); //result[0] == document
expect(result[2]).to.be(window); //result[0] == window
expect(CSSselect([CSSselect('#pseudos div.odd', document), CSSselect('#pseudos div.even', document)])).to.have.length(6); //found all the odd and even divs
}
},
*/
'is()': {
'simple selectors': function () {
expect(CSSselect.is(el, 'li')).to.be.ok(); //tag
expect(CSSselect.is(el, '*')).to.be.ok(); //wildcard
expect(CSSselect.is(el, '#attr-child-boosh')).to.be.ok(); //#id
expect(CSSselect.is(el, '[attr]')).to.be.ok(); //[attr]
expect(CSSselect.is(el, '[attr=boosh]')).to.be.ok(); //[attr=val]
expect(CSSselect.is(el, 'div')).to.not.be.ok(); //wrong tag
expect(CSSselect.is(el, '#foo')).to.not.be.ok(); //wrong #id
expect(CSSselect.is(el, '[foo]')).to.not.be.ok(); //wrong [attr]
expect(CSSselect.is(el, '[attr=foo]')).to.not.be.ok(); //wrong [attr=val]
},
'selector sequences': function () {
expect(CSSselect.is(el, 'li#attr-child-boosh[attr=boosh]')).to.be.ok(); //tag#id[attr=val]
expect(CSSselect.is(el, 'div#attr-child-boosh[attr=boosh]')).to.not.be.ok(); //wrong tag#id[attr=val]
},
'selector sequences combinators': function () {
expect(CSSselect.is(el, 'ol li')).to.be.ok(); //tag tag
expect(CSSselect.is(el, 'ol>li')).to.be.ok(); //tag>tag
expect(CSSselect.is(el, 'ol>li+li')).to.be.ok(); //tab>tag+tag
expect(CSSselect.is(el, 'ol#list li#attr-child-boosh[attr=boosh]')).to.be.ok(); //tag#id tag#id[attr=val]
expect(CSSselect.is(el, 'ol#list>li#attr-child-boosh[attr=boosh]')).to.not.be.ok(); //wrong tag#id>tag#id[attr=val]
expect(CSSselect.is(el, 'ol ol li#attr-child-boosh[attr=boosh]')).to.be.ok(); //tag tag tag#id[attr=val]
expect(CSSselect.is(CSSselect('#token-four', document)[0], 'div#fixtures>div a')).to.be.ok(); //tag#id>tag tag where ambiguous middle tag requires backtracking
},
'pseudos': function() {
//TODO: more tests!
expect(CSSselect.is(el, 'li:contains(hello)')).to.be.ok(); //matching :contains(text)
expect(CSSselect.is(el, 'li:contains(human)')).to.not.be.ok(); //non-matching :contains(text)
expect(CSSselect.is(CSSselect('#list>li', document)[2], ':humanoid')).to.be.ok(); //matching custom pseudo
expect(CSSselect.is(CSSselect('#list>li', document)[1], ':humanoid')).to.not.be.ok(); //non-matching custom pseudo
}/*,
'context': function () {
expect(CSSselect.is(el, 'li#attr-child-boosh[attr=boosh]', CSSselect('#list', document)[0])).to.be.ok(); //context
expect(CSSselect.is(el, 'ol#list li#attr-child-boosh[attr=boosh]', CSSselect('#boosh', document)[0])).to.not.be.ok(); //wrong context
}*/
},
'selecting elements in other documents': {
'get element by id': function () {
var result = CSSselect('#hsoob', doc);
expect(result[0]).to.be.ok(); //found element with id=hsoob
},
'get elements by class': function () {
expect(CSSselect('#hsoob .a', doc)).to.have.length(2); //found two elements
expect(CSSselect('#hsoob div.a', doc)[0]).to.be.ok(); //found one element
expect(CSSselect('#hsoob div', doc)).to.have.length(2); //found two {div} elements
expect(CSSselect('#hsoob span', doc)[0]).to.be.ok(); //found one {span} element
expect(CSSselect('#hsoob div div', doc)[0]).to.be.ok(); //found a single div
expect(CSSselect('p.odd', doc)).to.have.length(1); //found single br
},
'complex selectors': function () {
expect(CSSselect('.d ~ .sib', doc)).to.have.length(2); //found one ~ sibling
expect(CSSselect('.a .d + .sib', doc)).to.have.length(1); //found 2 + siblings
expect(CSSselect('#hsoob > div > .h', doc)).to.have.length(1); //found span using child selectors
expect(CSSselect('.a .d ~ .sib[test="f g"]', doc)).to.have.length(1); //found 1 ~ sibling with test attribute
},
'byId sub-queries': function () {
expect(CSSselect('#hsoob #spanny', doc)).to.have.length(1); //found "#id #id" in frame
expect(CSSselect('.a #spanny', doc)).to.have.length(1); //found ".class #id" in frame
expect(CSSselect('.a #booshTest #spanny', doc)).to.have.length(1); //found ".class #id #id" in frame
//expect(CSSselect('> #hsoob', doc)).to.have.length(1) //found "> #id" in frame
},
'byId sub-queries within sub-context': function () {
expect(CSSselect('#spanny', CSSselect('#hsoob', doc))).to.have.length(1); //found "#id -> #id" in frame
expect(CSSselect('.a #spanny', CSSselect('#hsoob', doc))).to.have.length(1); //found ".class #id" in frame
expect(CSSselect('.a #booshTest #spanny', CSSselect('#hsoob', doc))).to.have.length(1); //found ".class #id #id" in frame
expect(CSSselect('.a > #booshTest', CSSselect('#hsoob', doc))).to.have.length(1); //found "> .class #id" in frame
expect(CSSselect('#booshTest', CSSselect('#spanny', doc)).length).to.not.be.ok(); //shouldn't find #booshTest (ancestor) within #spanny (descendent)
expect(CSSselect('#booshTest', CSSselect('#lonelyHsoob', doc)).length).to.not.be.ok(); //shouldn't find #booshTest within #lonelyHsoob (unrelated)
}
}
};

View File

@ -1 +0,0 @@
<?xml version=1.0 encoding=UTF-8?> <soap:Envelope xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/ xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance> <soap:Body> <jsconf xmlns=http://www.example.com/ns1> <response xmlns:ab=http://www.example.com/ns2> <meta> <component id=seite1 class=component> <properties xmlns:cd=http://www.example.com/ns3> <property name=prop1> <thing /> <value>1</value> </property> <property name=prop2> <thing att=something /> </property> <foo_bar>foo</foo_bar> </properties> </component> </meta> </response> </jsconf> </soap:Body> </soap:Envelope>

View File

@ -1,247 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr" id="html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Sizzle Test Suite</title>
<link rel="Stylesheet" media="screen" href="../bower_components/qunit/qunit/qunit.css" />
<script type="text/javascript" src="../bower_components/qunit/qunit/qunit.js"></script>
<script type="text/javascript" src="data/testinit.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="../dist/sizzle.js"></script>
<script type="text/javascript" src="unit/selector.js"></script>
<script type="text/javascript" src="unit/utilities.js"></script>
<script type="text/javascript" src="unit/extending.js"></script>
</head>
<body id="body">
<div id="qunit">
<h1 id="qunit-header">jQuery Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
</div>
<!-- Test HTML -->
<dl id="dl" style="position:absolute;top:-32767px;left:-32767px;width:1px">
<div id="qunit-fixture">
<p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p>
<p id="ap">
Here are some [links] in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>,
<a id="groups" href="http://groups.google.com/" class="GROUPS">Google Groups (Link)</a>.
This link has <code id="code1"><a href="http://smin" id="anchor1">class="blog"</a></code>:
<a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a>
</p>
<div id="foo">
<p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p>
<p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p>
<p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p>
</div>
<div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv">
<div id="nothiddendivchild"></div>
</div>
<span id="name+value"></span>
<p id="first">Try them out:</p>
<ul id="firstUL"></ul>
<ol id="empty"><!-- comment --></ol>
<form id="form" action="formaction">
<label for="action" id="label-for">Action:</label>
<input type="text" name="action" value="Test" id="text1" maxlength="30"/>
<input type="text" name="text2" value="Test" id="text2" disabled="disabled"/>
<input type="radio" name="radio1" id="radio1" value="on"/>
<input type="radio" name="radio2" id="radio2" checked="checked"/>
<input type="checkbox" name="check" id="check1" checked="checked"/>
<input type="checkbox" id="check2" value="on"/>
<input type="hidden" name="hidden" id="hidden1"/>
<input type="text" style="display:none;" name="foo[bar]" id="hidden2"/>
<input type="text" id="name" name="name" value="name" />
<input type="search" id="search" name="search" value="search" />
<button id="button" name="button" type="button">Button</button>
<textarea id="area1" maxlength="30">foobar</textarea>
<select name="select1" id="select1">
<option id="option1a" class="emptyopt" value="">Nothing</option>
<option id="option1b" value="1">1</option>
<option id="option1c" value="2">2</option>
<option id="option1d" value="3">3</option>
</select>
<select name="select2" id="select2">
<option id="option2a" class="emptyopt" value="">Nothing</option>
<option id="option2b" value="1">1</option>
<option id="option2c" value="2">2</option>
<option id="option2d" selected="selected" value="3">3</option>
</select>
<select name="select3" id="select3" multiple="multiple">
<option id="option3a" class="emptyopt" value="">Nothing</option>
<option id="option3b" selected="selected" value="1">1</option>
<option id="option3c" selected="selected" value="2">2</option>
<option id="option3d" value="3">3</option>
<option id="option3e">no value</option>
</select>
<select name="select4" id="select4" multiple="multiple">
<optgroup disabled="disabled">
<option id="option4a" class="emptyopt" value="">Nothing</option>
<option id="option4b" disabled="disabled" selected="selected" value="1">1</option>
<option id="option4c" selected="selected" value="2">2</option>
</optgroup>
<option selected="selected" disabled="disabled" id="option4d" value="3">3</option>
<option id="option4e">no value</option>
</select>
<select name="select5" id="select5">
<option id="option5a" value="3">1</option>
<option id="option5b" value="2">2</option>
<option id="option5c" value="1">3</option>
</select>
<object id="object1" codebase="stupid">
<param name="p1" value="x1" />
<param name="p2" value="x2" />
</object>
<span id="台北Táiběi"></span>
<span id="台北" lang="中文"></span>
<span id="utf8class1" class="台北Táiběi 台北"></span>
<span id="utf8class2" class="台北"></span>
<span id="foo:bar" class="foo:bar"><span id="foo_descendent"></span></span>
<span id="test.foo[5]bar" class="test.foo[5]bar"></span>
<foo_bar id="foobar">test element</foo_bar>
</form>
<b id="floatTest">Float test.</b>
<iframe id="iframe" name="iframe"></iframe>
<form id="lengthtest">
<input type="text" id="length" name="test"/>
<input type="text" id="idTest" name="id"/>
</form>
<table id="table"></table>
<form id="name-tests">
<!-- Inputs with a grouped name attribute. -->
<input name="types[]" id="types_all" type="checkbox" value="all" />
<input name="types[]" id="types_anime" type="checkbox" value="anime" />
<input name="types[]" id="types_movie" type="checkbox" value="movie" />
</form>
<form id="testForm" action="#" method="get">
<textarea name="T3" rows="2" cols="15">?
Z</textarea>
<input type="hidden" name="H1" value="x" />
<input type="hidden" name="H2" />
<input name="PWD" type="password" value="" />
<input name="T1" type="text" />
<input name="T2" type="text" value="YES" readonly="readonly" />
<input type="checkbox" name="C1" value="1" />
<input type="checkbox" name="C2" />
<input type="radio" name="R1" value="1" />
<input type="radio" name="R1" value="2" />
<input type="text" name="My Name" value="me" />
<input type="reset" name="reset" value="NO" />
<select name="S1">
<option value="abc">ABC</option>
<option value="abc">ABC</option>
<option value="abc">ABC</option>
</select>
<select name="S2" multiple="multiple" size="3">
<option value="abc">ABC</option>
<option value="abc">ABC</option>
<option value="abc">ABC</option>
</select>
<select name="S3">
<option selected="selected">YES</option>
</select>
<select name="S4">
<option value="" selected="selected">NO</option>
</select>
<input type="submit" name="sub1" value="NO" />
<input type="submit" name="sub2" value="NO" />
<input type="image" name="sub3" value="NO" />
<button name="sub4" type="submit" value="NO">NO</button>
<input name="D1" type="text" value="NO" disabled="disabled" />
<input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" />
<input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" />
<select name="D4" disabled="disabled">
<option selected="selected" value="NO">NO</option>
</select>
<input id="list-test" type="text" />
<datalist id="datalist">
<option value="option"></option>
</datalist>
</form>
<div id="moretests">
<form>
<div id="checkedtest" style="display:none;">
<input type="radio" name="checkedtestradios" checked="checked"/>
<input type="radio" name="checkedtestradios" value="on"/>
<input type="checkbox" name="checkedtestcheckboxes" checked="checked"/>
<input type="checkbox" name="checkedtestcheckboxes" />
</div>
</form>
<div id="nonnodes"><span>hi</span> there <!-- mon ami --></div>
<div id="t2037">
<div><div class="hidden">hidden</div></div>
</div>
<div id="t6652">
<div></div>
</div>
<div id="t12087">
<input type="hidden" id="el12087" data-comma="0,1"/>
</div>
<div id="no-clone-exception"><object><embed></embed></object></div>
<div id="names-group">
<span id="name-is-example" name="example"></span>
<span id="name-is-div" name="div"></span>
</div>
<script id="script-no-src"></script>
<script id="script-src" src="http://src.test/path"></script>
<div id="id-name-tests">
<a id="tName1ID" name="tName1"><span></span></a>
<a id="tName2ID" name="tName2"><span></span></a>
<div id="tName1"><span id="tName1-span">C</span></div>
</div>
</div>
<div id="tabindex-tests">
<ol id="listWithTabIndex" tabindex="5">
<li id="foodWithNegativeTabIndex" tabindex="-1">Rice</li>
<li id="foodNoTabIndex">Beans</li>
<li>Blinis</li>
<li>Tofu</li>
</ol>
<div id="divWithNoTabIndex">I'm hungry. I should...</div>
<span>...</span><a href="#" id="linkWithNoTabIndex">Eat lots of food</a><span>...</span> |
<span>...</span><a href="#" id="linkWithTabIndex" tabindex="2">Eat a little food</a><span>...</span> |
<span>...</span><a href="#" id="linkWithNegativeTabIndex" tabindex="-1">Eat no food</a><span>...</span>
<span>...</span><a id="linkWithNoHrefWithNoTabIndex">Eat a burger</a><span>...</span>
<span>...</span><a id="linkWithNoHrefWithTabIndex" tabindex="1">Eat some funyuns</a><span>...</span>
<span>...</span><a id="linkWithNoHrefWithNegativeTabIndex" tabindex="-1">Eat some funyuns</a><span>...</span>
</div>
<div id="liveHandlerOrder">
<span id="liveSpan1"><a href="#" id="liveLink1"></a></span>
<span id="liveSpan2"><a href="#" id="liveLink2"></a></span>
</div>
<div id="siblingTest">
<em id="siblingfirst">1</em>
<em id="siblingnext">2</em>
<em id="siblingthird">
<em id="siblingchild">
<em id="siblinggrandchild">
<em id="siblinggreatgrandchild"></em>
</em>
</em>
</em>
<span id="siblingspan"></span>
</div>
</div>
</dl>
<br id="last"/>
</body>
</html>

View File

@ -1,87 +0,0 @@
var assert = require("assert"),
util = require("util"),
helper = require("../../tools/helper.js"),
CSSselect = helper.CSSselect,
path = require("path"),
docPath = path.join(__dirname, "index.html"),
document = null;
//in this module, the only use-case is to compare arrays of
function deepEqual(a, b, msg){
try {
assert.deepEqual(a, b, msg);
} catch(e) {
function getId(n){return n && n.attribs.id; }
e.actual = JSON.stringify(a.map(getId), 0, 2);
e.expected = JSON.stringify(b.map(getId), 0, 2);
throw e;
}
}
function loadDoc(){
return document = helper.getDocument(docPath);
}
module.exports = {
q: q,
t: t,
loadDoc: loadDoc,
createWithFriesXML: createWithFriesXML
};
/**
* Returns an array of elements with the given IDs
* @example q("main", "foo", "bar")
* @result [<div id="main">, <span id="foo">, <input id="bar">]
*/
function q() {
var r = [],
i = 0;
for ( ; i < arguments.length; i++ ) {
r.push( document.getElementById( arguments[i] ) );
}
return r;
}
/**
* Asserts that a select matches the given IDs
* @param {String} a - Assertion name
* @param {String} b - Sizzle selector
* @param {String} c - Array of ids to construct what is expected
* @example t("Check for something", "//[a]", ["foo", "baar"]);
* @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
*/
function t( a, b, c ) {
var f = CSSselect(b, document),
s = "",
i = 0;
for ( ; i < f.length; i++ ) {
s += ( s && "," ) + '"' + f[ i ].id + '"';
}
deepEqual(f, q.apply( q, c ), a + " (" + b + ")");
}
/**
* Add random number to url to stop caching
*
* @example url("data/test.html")
* @result "data/test.html?10538358428943"
*
* @example url("data/test.php?foo=bar")
* @result "data/test.php?foo=bar&10538358345554"
*/
function url( value ) {
return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
}
var xmlDoc = helper.getDOMFromPath(path.join(__dirname, "fries.xml"), { xmlMode: true });
var filtered = xmlDoc.filter(function(t){return t.type === "tag"});
xmlDoc.lastChild = filtered[filtered.length - 1];
function createWithFriesXML() {
return xmlDoc;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
describe("nwmatcher", function(){
require("./nwmatcher/");
});
describe("sizzle", function(){
describe("selector", function(){
require("./sizzle/selector");
});
});
describe("qwery", function(){
exportsRun(require("./qwery/"));
});
function exportsRun(mod){
Object.keys(mod).forEach(function(name){
if(typeof mod[name] === "object") describe(name, function(){
exportsRun(mod[name]);
});
else it(name, mod[name]);
});
}

View File

@ -1,10 +0,0 @@
var ben = require("ben"),
testString = "doo, *#foo > elem.bar[class$=bAz i]:not([ id *= \"2\" ]):nth-child(2n)",
helper = require("./helper.js"),
CSSselect = helper.CSSselect,
compile = CSSselect.compile,
dom = helper.getDefaultDom();
//console.log("Parsing took:", ben(1e5, function(){compile(testString);}));
var compiled = compile(testString);
console.log("Executing took:", ben(1e6, function(){CSSselect(compiled, dom);})*1e3);

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
var fs = require("fs"),
path = require("path"),
htmlparser2 = require("htmlparser2"),
DomUtils = htmlparser2.DomUtils,
CSSselect = require("../../");
function getDOMFromPath(path, options){
return htmlparser2.parseDOM(fs.readFileSync(path).toString(), options);
}
module.exports = {
CSSselect: CSSselect,
getFile: function(name, options){
return getDOMFromPath(path.join(__dirname, "docs", name), options);
},
getDOMFromPath: getDOMFromPath,
getDOM: htmlparser2.parseDOM,
getDefaultDom: function(){
return htmlparser2.parseDOM(
"<elem id=foo><elem class='bar baz'><tag class='boom'> This is some simple text </tag></elem></elem>"
);
},
getDocument: function(path){
var document = getDOMFromPath(path);
document.getElementsByTagName = function(name){
return DomUtils.getElementsByTagName("*", document);
};
document.getElementById = function(id){
return DomUtils.getElementById(id, document);
};
document.createTextNode = function(content){
return {
type: "text",
data: "content"
};
};
document.createElement = function(name){
return {
type: "tag",
name: name,
children: [],
attribs: {}
};
};
document.body = DomUtils.getElementsByTagName("body", document, true, 1)[0];
document.documentElement = document.filter(DomUtils.isTag)[0];
return document;
}
};

View File

@ -1,76 +0,0 @@
var helper = require("./helper.js"),
doc = helper.getFile("W3C_Selectors.html"),
CSSselect = helper.CSSselect,
soupselect = require("cheerio-soupselect"),
selectors = ["body", "div", "body div", "div p", "div > p", "div + p", "div ~ p", "div[class^=exa][class$=mple]", "div p a", "div, p, a", ".note", "div.example", "ul .tocline2", "div.example, div.note", "#title", "h1#title", "div #title", "ul.toc li.tocline2", "ul.toc > li.tocline2", "h1#title + div > p", "h1[id]:contains(Selectors)", "a[href][lang][class]", "div[class]", "div[class=example]", "div[class^=exa]", "div[class$=mple]", "div[class*=e]", "div[class|=dialog]", "div[class!=made_up]", "div[class~=example]"/*, "div:not(.example)", "p:contains(selectors)", "p:nth-child(even)", "p:nth-child(2n)", "p:nth-child(odd)", "p:nth-child(2n+1)", "p:nth-child(n)", "p:only-child", "p:last-child", "p:first-child"*/];
var engines = [function(a,b){return CSSselect(b,a);}, soupselect.select];
//returns true when an error occurs
function testResult(rule, index){
var results = engines
.map(function(func){ return func(doc, rule); });
//check if both had the same result
for(var i = 1; i < results.length; i++){
//TODO: might be hard to debug with more engines
if(results[i-1].length !== results[i].length){
//console.log(rule, results[i-1].length, results[i].length);
return true;
}
for(var j = 0; j < results[i].length; j++){
if(results[i-1][j] !== results[i][j]){
if(results[i-1].indexOf(results[i][j]) === -1){
return true;
}
}
}
//require("assert").deepEqual(results[i-1], results[i], rule + ": not the same elements");
}
return false;
}
selectors.filter(testResult).forEach(function(rule){ print(rule, "failed!\n"); });
process.exit(0); //don't run speed tests
print("-----\n\nChecking performance\n\n");
//test the speed
var ben = require("ben");
function testSpeed(rule){
print(rule, Array(28-rule.length).join(" "));
var results = engines
.map(function(func){ return function(){ return func(doc, rule); }});
//also add a precompiled CSSselect test
var compiled = CSSselect(rule);
results.unshift(function(){ return CSSselect.iterate(compiled, doc); });
results = results.map(ben);
var min = Math.min.apply(null, results);
var max = Math.max.apply(null, results);
results.forEach(function(result){
if(result === min) return print(" +", result, "+");
if(result === max) return print(" !", result, "!");
if(Math.abs(result-min) > Math.abs(result-max)){
return print(" =", result, "=");
}
print(" ~", result, "~");
});
print("\n");
}
print("RULE ", "CSSselect (pc)", "CSSselect", "soupselect\n");
selectors.forEach(testSpeed);
function print(){
process.stdout.write(Array.prototype.join.call(arguments, " "));
}

View File

@ -1,4 +0,0 @@
language: node_js
node_js:
- "0.10"
- 0.11

View File

@ -1,182 +0,0 @@
/*
Module dependencies
*/
var ElementType = require('domelementtype');
var entities = require('entities');
/*
Boolean Attributes
*/
var booleanAttributes = {
__proto__: null,
allowfullscreen: true,
async: true,
autofocus: true,
autoplay: true,
checked: true,
controls: true,
default: true,
defer: true,
disabled: true,
hidden: true,
ismap: true,
loop: true,
multiple: true,
muted: true,
open: true,
readonly: true,
required: true,
reversed: true,
scoped: true,
seamless: true,
selected: true,
typemustmatch: true
};
var unencodedElements = {
__proto__: null,
style: true,
script: true,
xmp: true,
iframe: true,
noembed: true,
noframes: true,
plaintext: true,
noscript: true
};
/*
Format attributes
*/
function formatAttrs(attributes, opts) {
if (!attributes) return;
var output = '',
value;
// Loop through the attributes
for (var key in attributes) {
value = attributes[key];
if (output) {
output += ' ';
}
if (!value && booleanAttributes[key]) {
output += key;
} else {
output += key + '="' + (opts.decodeEntities ? entities.encodeXML(value) : value) + '"';
}
}
return output;
}
/*
Self-enclosing tags (stolen from node-htmlparser)
*/
var singleTag = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
command: true,
embed: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true,
//common self closing svg elements
path: true,
circle: true,
ellipse: true,
line: true,
rect: true,
use: true
};
var render = module.exports = function(dom, opts) {
if (!Array.isArray(dom) && !dom.cheerio) dom = [dom];
opts = opts || {};
var output = '';
for(var i = 0; i < dom.length; i++){
var elem = dom[i];
if (elem.type === 'root')
output += render(elem.children, opts);
else if (ElementType.isTag(elem))
output += renderTag(elem, opts);
else if (elem.type === ElementType.Directive)
output += renderDirective(elem);
else if (elem.type === ElementType.Comment)
output += renderComment(elem);
else if (elem.type === ElementType.CDATA)
output += renderCdata(elem);
else
output += renderText(elem, opts);
}
return output;
};
function renderTag(elem, opts) {
var tag = '<' + elem.name,
attribs = formatAttrs(elem.attribs, opts);
if (attribs) {
tag += ' ' + attribs;
}
if (
opts.xmlMode &&
(!elem.children || elem.children.length === 0)
) {
tag += '/>';
} else {
tag += '>';
tag += render(elem.children, opts);
if (!singleTag[elem.name] || opts.xmlMode) {
tag += '</' + elem.name + '>';
}
}
return tag;
}
function renderDirective(elem) {
return '<' + elem.data + '>';
}
function renderText(elem, opts) {
var data = elem.data || '';
// if entities weren't decoded, no need to encode them back
if (opts.decodeEntities && !(elem.parent && elem.parent.name in unencodedElements)) {
data = entities.encodeXML(data);
}
return data;
}
function renderCdata(elem) {
return '<![CDATA[' + elem.children[0].data + ']]>';
}
function renderComment(elem) {
return '<!--' + elem.data + '-->';
}

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,14 +0,0 @@
//Types of elements found in the DOM
module.exports = {
Text: "text", //Text
Directive: "directive", //<? ... ?>
Comment: "comment", //<!-- ... -->
Script: "script", //<script> tags
Style: "style", //<style> tags
Tag: "tag", //Any tag
CDATA: "cdata", //<![CDATA[ ... ]]>
isTag: function(elem){
return elem.type === "tag" || elem.type === "script" || elem.type === "style";
}
};

View File

@ -1,25 +0,0 @@
{
"name": "domelementtype",
"version": "1.1.1",
"description": "all the types of nodes in htmlparser2's dom",
"main": "index.js",
"repository": {
"type": "git",
"url": "git://github.com/FB55/domelementtype.git"
},
"keywords": [
"dom",
"htmlparser2"
],
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"readme": "all the types of nodes in htmlparser2's dom\n",
"readmeFilename": "readme.md",
"bugs": {
"url": "https://github.com/FB55/domelementtype/issues"
},
"_id": "domelementtype@1.1.1",
"_from": "domelementtype@~1.1.1"
}

View File

@ -1 +0,0 @@
all the types of nodes in htmlparser2's dom

View File

@ -1,39 +0,0 @@
{
"name": "dom-serializer",
"version": "0.0.1",
"description": "render dom nodes to string",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"keywords": [
"html",
"xml",
"render"
],
"repository": {
"type": "git",
"url": "git://github.com/cheeriojs/dom-renderer.git"
},
"main": "./index.js",
"dependencies": {
"domelementtype": "~1.1.1",
"entities": "~1.1.1"
},
"devDependencies": {
"mocha": "*",
"expect.js": "~0.3.1",
"lodash": "~2.4.1",
"jshint": "~2.3.0",
"cheerio": "*"
},
"scripts": {
"test": "mocha test.js"
},
"bugs": {
"url": "https://github.com/cheeriojs/dom-renderer/issues"
},
"readme": "ERROR: No README data found!",
"_id": "dom-serializer@0.0.1",
"_from": "dom-serializer@~0.0.0"
}

View File

@ -1,103 +0,0 @@
var expect = require('expect.js'),
defaultOpts = require('cheerio').prototype.options,
_ = require('lodash'),
parse = require('cheerio/lib/parse'),
render = require('./index.js');
var html = function(preset, str, options) {
options = _.defaults(options || {}, _.defaults(preset, defaultOpts));
var dom = parse(str, options);
return render(dom, options);
};
var xml = function(str, options) {
options = _.defaults(options || {}, defaultOpts);
options.xmlMode = true;
var dom = parse(str, options);
return render(dom, options);
};
describe('render', function() {
// only test applicable to the default setup
describe('(html)', function() {
var htmlFunc = _.partial(html, {});
// it doesn't really make sense for {decodeEntities: false}
// since currently it will convert <hr class='blah'> into <hr class="blah"> anyway.
it('should handle double quotes within single quoted attributes properly', function() {
var str = '<hr class=\'an "edge" case\' />';
expect(htmlFunc(str)).to.equal('<hr class="an &quot;edge&quot; case">');
});
});
// run html with default options
describe('(html, {})', _.partial( testBody, _.partial(html, {}) ));
// run html with turned off decodeEntities
describe('(html, {decodeEntities: false})', _.partial( testBody, _.partial(html, {decodeEntities: false}) ));
describe('(xml)', function() {
it('should render CDATA correctly', function() {
var str = '<a> <b> <![CDATA[ asdf&asdf ]]> <c/> <![CDATA[ asdf&asdf ]]> </b> </a>';
expect(xml(str)).to.equal(str);
});
});
});
function testBody(html) {
it('should render <br /> tags correctly', function() {
var str = '<br />';
expect(html(str)).to.equal('<br>');
});
it('should retain encoded HTML content within attributes', function() {
var str = '<hr class="cheerio &amp; node = happy parsing" />';
expect(html(str)).to.equal('<hr class="cheerio &amp; node = happy parsing">');
});
it('should shorten the "checked" attribute when it contains the value "checked"', function() {
var str = '<input checked/>';
expect(html(str)).to.equal('<input checked>');
});
it('should not shorten the "name" attribute when it contains the value "name"', function() {
var str = '<input name="name"/>';
expect(html(str)).to.equal('<input name="name">');
});
it('should render comments correctly', function() {
var str = '<!-- comment -->';
expect(html(str)).to.equal('<!-- comment -->');
});
it('should render whitespace by default', function() {
var str = '<a href="./haha.html">hi</a> <a href="./blah.html">blah</a>';
expect(html(str)).to.equal(str);
});
it('should normalize whitespace if specified', function() {
var str = '<a href="./haha.html">hi</a> <a href="./blah.html">blah </a>';
expect(html(str, { normalizeWhitespace: true })).to.equal('<a href="./haha.html">hi</a> <a href="./blah.html">blah </a>');
});
it('should preserve multiple hyphens in data attributes', function() {
var str = '<div data-foo-bar-baz="value"></div>';
expect(html(str)).to.equal('<div data-foo-bar-baz="value"></div>');
});
it('should not encode characters in script tag', function() {
var str = '<script>alert("hello world")</script>';
expect(html(str)).to.equal(str);
});
it('should not encode json data', function() {
var str = '<script>var json = {"simple_value": "value", "value_with_tokens": "&quot;here & \'there\'&quot;"};</script>';
expect(html(str)).to.equal(str);
});
}

View File

@ -1,7 +0,0 @@
language: node_js
node_js:
- 0.8
- "0.10"
- 0.11
script: npm run coveralls

View File

@ -1,11 +0,0 @@
Copyright (c) Felix Böhm
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,33 +0,0 @@
var encode = require("./lib/encode.js"),
decode = require("./lib/decode.js");
exports.decode = function(data, level){
return (!level || level <= 0 ? decode.XML : decode.HTML)(data);
};
exports.decodeStrict = function(data, level){
return (!level || level <= 0 ? decode.XML : decode.HTMLStrict)(data);
};
exports.encode = function(data, level){
return (!level || level <= 0 ? encode.XML : encode.HTML)(data);
};
exports.encodeXML = encode.XML;
exports.encodeHTML4 =
exports.encodeHTML5 =
exports.encodeHTML = encode.HTML;
exports.decodeXML =
exports.decodeXMLStrict = decode.XML;
exports.decodeHTML4 =
exports.decodeHTML5 =
exports.decodeHTML = decode.HTML;
exports.decodeHTML4Strict =
exports.decodeHTML5Strict =
exports.decodeHTMLStrict = decode.HTMLStrict;
exports.escape = encode.escape;

View File

@ -1,72 +0,0 @@
var entityMap = require("../maps/entities.json"),
legacyMap = require("../maps/legacy.json"),
xmlMap = require("../maps/xml.json"),
decodeCodePoint = require("./decode_codepoint.js");
var decodeXMLStrict = getStrictDecoder(xmlMap),
decodeHTMLStrict = getStrictDecoder(entityMap);
function getStrictDecoder(map){
var keys = Object.keys(map).join("|"),
replace = getReplacer(map);
keys += "|#[xX][\\da-fA-F]+|#\\d+";
var re = new RegExp("&(?:" + keys + ");", "g");
return function(str){
return String(str).replace(re, replace);
};
}
var decodeHTML = (function(){
var legacy = Object.keys(legacyMap)
.sort(sorter);
var keys = Object.keys(entityMap)
.sort(sorter);
for(var i = 0, j = 0; i < keys.length; i++){
if(legacy[j] === keys[i]){
keys[i] += ";?";
j++;
} else {
keys[i] += ";";
}
}
var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"),
replace = getReplacer(entityMap);
function replacer(str){
if(str.substr(-1) !== ";") str += ";";
return replace(str);
}
//TODO consider creating a merged map
return function(str){
return String(str).replace(re, replacer);
};
}());
function sorter(a, b){
return a < b ? 1 : -1;
}
function getReplacer(map){
return function replace(str){
if(str.charAt(1) === "#"){
if(str.charAt(2) === "X" || str.charAt(2) === "x"){
return decodeCodePoint(parseInt(str.substr(3), 16));
}
return decodeCodePoint(parseInt(str.substr(2), 10));
}
return map[str.slice(1, -1)];
};
}
module.exports = {
XML: decodeXMLStrict,
HTML: decodeHTML,
HTMLStrict: decodeHTMLStrict
};

View File

@ -1,26 +0,0 @@
var decodeMap = require("../maps/decode.json");
module.exports = decodeCodePoint;
// modified version of https://github.com/mathiasbynens/he/blob/master/src/he.js#L94-L119
function decodeCodePoint(codePoint){
if((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF){
return "\uFFFD";
}
if(codePoint in decodeMap){
codePoint = decodeMap[codePoint];
}
var output = "";
if(codePoint > 0xFFFF){
codePoint -= 0x10000;
output += String.fromCharCode(codePoint >>> 10 & 0x3FF | 0xD800);
codePoint = 0xDC00 | codePoint & 0x3FF;
}
output += String.fromCharCode(codePoint);
return output;
}

View File

@ -1,73 +0,0 @@
var inverseXML = getInverseObj(require("../maps/xml.json")),
xmlReplacer = getInverseReplacer(inverseXML);
exports.XML = getInverse(inverseXML, xmlReplacer);
var inverseHTML = getInverseObj(require("../maps/entities.json")),
htmlReplacer = getInverseReplacer(inverseHTML);
exports.HTML = getInverse(inverseHTML, htmlReplacer);
function getInverseObj(obj){
return Object.keys(obj).sort().reduce(function(inverse, name){
inverse[obj[name]] = "&" + name + ";";
return inverse;
}, {});
}
function getInverseReplacer(inverse){
var single = [],
multiple = [];
Object.keys(inverse).forEach(function(k){
if(k.length === 1){
single.push("\\" + k);
} else {
multiple.push(k);
}
});
//TODO add ranges
multiple.unshift("[" + single.join("") + "]");
return new RegExp(multiple.join("|"), "g");
}
var re_nonASCII = /[^\0-\x7F]/g,
re_astralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
function singleCharReplacer(c){
return "&#x" + c.charCodeAt(0).toString(16).toUpperCase() + ";";
}
function astralReplacer(c){
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
var high = c.charCodeAt(0);
var low = c.charCodeAt(1);
var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000;
return "&#x" + codePoint.toString(16).toUpperCase() + ";";
}
function getInverse(inverse, re){
function func(name){
return inverse[name];
}
return function(data){
return data
.replace(re, func)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
};
}
var re_xmlChars = getInverseReplacer(inverseXML);
function escapeXML(data){
return data
.replace(re_xmlChars, singleCharReplacer)
.replace(re_astralSymbols, astralReplacer)
.replace(re_nonASCII, singleCharReplacer);
}
exports.escape = escapeXML;

View File

@ -1 +0,0 @@
{"0":65533,"128":8364,"130":8218,"131":402,"132":8222,"133":8230,"134":8224,"135":8225,"136":710,"137":8240,"138":352,"139":8249,"140":338,"142":381,"145":8216,"146":8217,"147":8220,"148":8221,"149":8226,"150":8211,"151":8212,"152":732,"153":8482,"154":353,"155":8250,"156":339,"158":382,"159":376}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
{"Aacute":"\u00C1","aacute":"\u00E1","Acirc":"\u00C2","acirc":"\u00E2","acute":"\u00B4","AElig":"\u00C6","aelig":"\u00E6","Agrave":"\u00C0","agrave":"\u00E0","amp":"&","AMP":"&","Aring":"\u00C5","aring":"\u00E5","Atilde":"\u00C3","atilde":"\u00E3","Auml":"\u00C4","auml":"\u00E4","brvbar":"\u00A6","Ccedil":"\u00C7","ccedil":"\u00E7","cedil":"\u00B8","cent":"\u00A2","copy":"\u00A9","COPY":"\u00A9","curren":"\u00A4","deg":"\u00B0","divide":"\u00F7","Eacute":"\u00C9","eacute":"\u00E9","Ecirc":"\u00CA","ecirc":"\u00EA","Egrave":"\u00C8","egrave":"\u00E8","ETH":"\u00D0","eth":"\u00F0","Euml":"\u00CB","euml":"\u00EB","frac12":"\u00BD","frac14":"\u00BC","frac34":"\u00BE","gt":">","GT":">","Iacute":"\u00CD","iacute":"\u00ED","Icirc":"\u00CE","icirc":"\u00EE","iexcl":"\u00A1","Igrave":"\u00CC","igrave":"\u00EC","iquest":"\u00BF","Iuml":"\u00CF","iuml":"\u00EF","laquo":"\u00AB","lt":"<","LT":"<","macr":"\u00AF","micro":"\u00B5","middot":"\u00B7","nbsp":"\u00A0","not":"\u00AC","Ntilde":"\u00D1","ntilde":"\u00F1","Oacute":"\u00D3","oacute":"\u00F3","Ocirc":"\u00D4","ocirc":"\u00F4","Ograve":"\u00D2","ograve":"\u00F2","ordf":"\u00AA","ordm":"\u00BA","Oslash":"\u00D8","oslash":"\u00F8","Otilde":"\u00D5","otilde":"\u00F5","Ouml":"\u00D6","ouml":"\u00F6","para":"\u00B6","plusmn":"\u00B1","pound":"\u00A3","quot":"\"","QUOT":"\"","raquo":"\u00BB","reg":"\u00AE","REG":"\u00AE","sect":"\u00A7","shy":"\u00AD","sup1":"\u00B9","sup2":"\u00B2","sup3":"\u00B3","szlig":"\u00DF","THORN":"\u00DE","thorn":"\u00FE","times":"\u00D7","Uacute":"\u00DA","uacute":"\u00FA","Ucirc":"\u00DB","ucirc":"\u00FB","Ugrave":"\u00D9","ugrave":"\u00F9","uml":"\u00A8","Uuml":"\u00DC","uuml":"\u00FC","Yacute":"\u00DD","yacute":"\u00FD","yen":"\u00A5","yuml":"\u00FF"}

View File

@ -1 +0,0 @@
{"amp":"&","apos":"'","gt":">","lt":"<","quot":"\""}

View File

@ -1,63 +0,0 @@
{
"name": "entities",
"version": "1.1.1",
"description": "Encode & decode XML/HTML entities with ease",
"author": {
"name": "Felix Boehm",
"email": "me@feedic.com"
},
"keywords": [
"html",
"xml",
"entity",
"encoding"
],
"main": "./index.js",
"directories": {
"test": "test"
},
"devDependencies": {
"mocha": "1",
"mocha-lcov-reporter": "*",
"coveralls": "*",
"istanbul": "*",
"jshint": "2"
},
"scripts": {
"test": "mocha && npm run lint",
"lint": "jshint index.js lib/*.js test/*.js",
"lcov": "istanbul cover _mocha --report lcovonly -- -R spec",
"coveralls": "npm run lint && npm run lcov && (cat coverage/lcov.info | coveralls || exit 0)"
},
"repository": {
"type": "git",
"url": "git://github.com/fb55/node-entities.git"
},
"license": "BSD-like",
"jshintConfig": {
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"noarg": true,
"nonbsp": true,
"quotmark": "double",
"undef": true,
"unused": true,
"trailing": true,
"eqnull": true,
"proto": true,
"smarttabs": true,
"node": true,
"globals": {
"describe": true,
"it": true
}
},
"readme": "#entities [![NPM version](http://img.shields.io/npm/v/entities.svg)](https://npmjs.org/package/entities) [![Downloads](https://img.shields.io/npm/dm/entities.svg)](https://npmjs.org/package/entities) [![Build Status](http://img.shields.io/travis/fb55/node-entities.svg)](http://travis-ci.org/fb55/node-entities) [![Coverage](http://img.shields.io/coveralls/fb55/node-entities.svg)](https://coveralls.io/r/fb55/node-entities)\n\nEn- & decoder for XML/HTML entities.\n\n##How to…\n\n###…install `entities`\n\n npm i entities\n\n###…use `entities`\n\n```javascript\nvar entities = require(\"entities\");\n//encoding\nentities.encodeXML(\"&#38;\"); // \"&amp;#38;\"\nentities.encodeHTML(\"&#38;\"); // \"&amp;&num;38&semi;\"\n//decoding\nentities.decodeXML(\"asdf &amp; &#xFF; &#xFC; &apos;\"); // \"asdf & ÿ ü '\"\nentities.decodeHTML(\"asdf &amp; &yuml; &uuml; &apos;\"); // \"asdf & ÿ ü '\"\n```\n\n<!-- TODO extend API -->\n\n---\n\nLicense: BSD-like\n",
"readmeFilename": "readme.md",
"bugs": {
"url": "https://github.com/fb55/node-entities/issues"
},
"_id": "entities@1.1.1",
"_from": "entities@~1.1.1"
}

View File

@ -1,27 +0,0 @@
#entities [![NPM version](http://img.shields.io/npm/v/entities.svg)](https://npmjs.org/package/entities) [![Downloads](https://img.shields.io/npm/dm/entities.svg)](https://npmjs.org/package/entities) [![Build Status](http://img.shields.io/travis/fb55/node-entities.svg)](http://travis-ci.org/fb55/node-entities) [![Coverage](http://img.shields.io/coveralls/fb55/node-entities.svg)](https://coveralls.io/r/fb55/node-entities)
En- & decoder for XML/HTML entities.
##How to…
###…install `entities`
npm i entities
###…use `entities`
```javascript
var entities = require("entities");
//encoding
entities.encodeXML("&#38;"); // "&amp;#38;"
entities.encodeHTML("&#38;"); // "&amp;&num;38&semi;"
//decoding
entities.decodeXML("asdf &amp; &#xFF; &#xFC; &apos;"); // "asdf & ÿ ü '"
entities.decodeHTML("asdf &amp; &yuml; &uuml; &apos;"); // "asdf & ÿ ü '"
```
<!-- TODO extend API -->
---
License: BSD-like

View File

@ -1,2 +0,0 @@
--check-leaks
--reporter spec

View File

@ -1,168 +0,0 @@
var assert = require("assert"),
path = require("path"),
entities = require("../");
describe("Encode->decode test", function(){
var testcases = [
{
input: "asdf & ÿ ü '",
xml: "asdf &amp; &#xFF; &#xFC; &apos;",
html: "asdf &amp; &yuml; &uuml; &apos;"
}, {
input: "&#38;",
xml: "&amp;#38;",
html: "&amp;&num;38&semi;"
},
];
testcases.forEach(function(tc) {
var encodedXML = entities.encodeXML(tc.input);
it("should XML encode " + tc.input, function(){
assert.equal(encodedXML, tc.xml);
});
it("should default to XML encode " + tc.input, function(){
assert.equal(entities.encode(tc.input), tc.xml);
});
it("should XML decode " + encodedXML, function(){
assert.equal(entities.decodeXML(encodedXML), tc.input);
});
it("should default to XML encode " + encodedXML, function(){
assert.equal(entities.decode(encodedXML), tc.input);
});
it("should default strict to XML encode " + encodedXML, function(){
assert.equal(entities.decodeStrict(encodedXML), tc.input);
});
var encodedHTML5 = entities.encodeHTML5(tc.input);
it("should HTML5 encode " + tc.input, function(){
assert.equal(encodedHTML5, tc.html);
});
it("should HTML5 decode " + encodedHTML5, function(){
assert.equal(entities.decodeHTML(encodedHTML5), tc.input);
});
});
it("should encode data URIs (issue 16)", function(){
var data = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAALAAABAAEAAAIBRAA7";
assert.equal(entities.decode(entities.encode(data)), data);
});
});
describe("Decode test", function(){
var testcases = [
{ input: "&amp;amp;", output: "&amp;" },
{ input: "&amp;#38;", output: "&#38;" },
{ input: "&amp;#x26;", output: "&#x26;" },
{ input: "&amp;#X26;", output: "&#X26;" },
{ input: "&#38;#38;", output: "&#38;" },
{ input: "&#x26;#38;", output: "&#38;" },
{ input: "&#X26;#38;", output: "&#38;" },
{ input: "&#x3a;", output: ":" },
{ input: "&#x3A;", output: ":" },
{ input: "&#X3a;", output: ":" },
{ input: "&#X3A;", output: ":" }
];
testcases.forEach(function(tc) {
it("should XML decode " + tc.input, function(){
assert.equal(entities.decodeXML(tc.input), tc.output);
});
it("should HTML4 decode " + tc.input, function(){
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
it("should HTML5 decode " + tc.input, function(){
assert.equal(entities.decodeHTML(tc.input), tc.output);
});
});
});
var levels = ["xml", "entities"];
describe("Documents", function(){
levels
.map(function(n){ return path.join("..", "maps", n); })
.map(require)
.forEach(function(doc, i){
describe("Decode", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decode("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Decode strict", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decodeStrict("&" + e + ";", l), doc[e]);
}
});
});
});
describe("Encode", function(){
it(levels[i], function(){
Object.keys(doc).forEach(function(e){
for(var l = i; l < levels.length; l++){
assert.equal(entities.decode(entities.encode(doc[e], l), l), doc[e]);
}
});
});
});
});
var legacy = require("../maps/legacy.json");
describe("Legacy", function(){
it("should decode", runLegacy);
});
function runLegacy(){
Object.keys(legacy).forEach(function(e){
assert.equal(entities.decodeHTML("&" + e), legacy[e]);
});
}
});
var astral = {
"1D306": "\uD834\uDF06",
"1D11E": "\uD834\uDD1E"
};
var astralSpecial = {
"80": "\u20AC",
"110000": "\uFFFD"
};
describe("Astral entities", function(){
Object.keys(astral).forEach(function(c){
it("should decode " + astral[c], function(){
assert.equal(entities.decode("&#x" + c + ";"), astral[c]);
});
it("should encode " + astral[c], function(){
assert.equal(entities.encode(astral[c]), "&#x" + c + ";");
});
it("should escape " + astral[c], function(){
assert.equal(entities.escape(astral[c]), "&#x" + c + ";");
});
});
Object.keys(astralSpecial).forEach(function(c){
it("special should decode \\u" + c, function(){
assert.equal(entities.decode("&#x" + c + ";"), astralSpecial[c]);
});
});
});
describe("Escape", function(){
it("should always decode ASCII chars", function(){
for(var i = 0; i < 0x7F; i++){
var c = String.fromCharCode(i);
assert.equal(entities.decodeXML(entities.escape(c)), c);
}
});
});

View File

@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text eol=lf

View File

@ -1,7 +0,0 @@
language: node_js
node_js:
- 0.8
- 0.10
- 0.11
script: npm run coveralls

View File

@ -1,18 +0,0 @@
Copyright 2010, 2011, Chris Winberry <chris@winberry.net>. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@ -1,83 +0,0 @@
#htmlparser2 [![NPM version](http://img.shields.io/npm/v/htmlparser2.svg)](https://npmjs.org/package/htmlparser2) [![Downloads](https://img.shields.io/npm/dm/htmlparser2.svg)](https://npmjs.org/package/htmlparser2)
[![Build Status](https://travis-ci.org/fb55/htmlparser2.svg)](http://travis-ci.org/fb55/htmlparser2) [![Coverage](http://img.shields.io/coveralls/fb55/htmlparser2.svg)](https://coveralls.io/r/fb55/htmlparser2)
A forgiving HTML/XML/RSS parser written in JS for NodeJS. The parser can handle streams (chunked data) and supports custom handlers for writing custom DOMs/output.
##Installing
npm install htmlparser2
A live demo of htmlparser2 is available at http://demos.forbeslindesay.co.uk/htmlparser2/
##Usage
```javascript
var htmlparser = require("htmlparser2");
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
console.log("JS! Hooray!");
}
},
ontext: function(text){
console.log("-->", text);
},
onclosetag: function(tagname){
if(tagname === "script"){
console.log("That's it?!");
}
}
});
parser.write("Xyz <script type='text/javascript'>var foo = '<<bar>>';</ script>");
parser.end();
```
Output (simplified):
```javascript
--> Xyz
JS! Hooray!
--> var foo = '<<bar>>';
That's it?!
```
Read more about the parser in the [wiki](https://github.com/fb55/htmlparser2/wiki/Parser-options).
##Get a DOM
The `DomHandler` (known as `DefaultHandler` in the original `htmlparser` module) produces a DOM (document object model) that can be manipulated using the [`DomUtils`](https://github.com/fb55/DomUtils) helper.
The `DomHandler`, while still bundled with this module, was moved to its [own module](https://github.com/fb55/domhandler). Have a look at it for further information.
##Parsing RSS/RDF/Atom Feeds
```javascript
new htmlparser.FeedHandler(function(<error> error, <object> feed){
...
});
```
##Performance
After having some artificial benchmarks for some time, __@AndreasMadsen__ published his [`htmlparser-benchmark`](https://github.com/AndreasMadsen/htmlparser-benchmark), which benchmarks HTML parses based on real-world websites.
At the time of writing, the latest versions of all supported parsers show the following performance characteristics on [Travis CI](https://travis-ci.org/AndreasMadsen/htmlparser-benchmark/builds/10805007) (please note that Travis doesn't guarantee equal conditions for all tests):
```
gumbo-parser : 34.9208 ms/file ± 21.4238
html-parser : 24.8224 ms/file ± 15.8703
html5 : 419.597 ms/file ± 264.265
htmlparser : 60.0722 ms/file ± 384.844
htmlparser2-dom: 12.0749 ms/file ± 6.49474
htmlparser2 : 7.49130 ms/file ± 5.74368
hubbub : 30.4980 ms/file ± 16.4682
libxmljs : 14.1338 ms/file ± 18.6541
parse5 : 22.0439 ms/file ± 15.3743
sax : 49.6513 ms/file ± 26.6032
```
##How is this different from [node-htmlparser](https://github.com/tautologistics/node-htmlparser)?
This is a fork of the `htmlparser` module. The main difference is that this is intended to be used only with node (it runs on other platforms using [browserify](https://github.com/substack/node-browserify)). `htmlparser2` was rewritten multiple times and, while it maintains an API that's compatible with `htmlparser` in most cases, the projects don't share any code anymore.
The parser now provides a callback interface close to [sax.js](https://github.com/isaacs/sax-js) (originally targeted at [readabilitySAX](https://github.com/fb55/readabilitysax)). As a result, old handlers won't work anymore.
The `DefaultHandler` and the `RssHandler` were renamed to clarify their purpose (to `DomHandler` and `FeedHandler`). The old names are still available when requiring `htmlparser2`, so your code should work as expected.

View File

@ -1,55 +0,0 @@
module.exports = CollectingHandler;
function CollectingHandler(cbs){
this._cbs = cbs || {};
this.events = [];
}
var EVENTS = require("./").EVENTS;
Object.keys(EVENTS).forEach(function(name){
if(EVENTS[name] === 0){
name = "on" + name;
CollectingHandler.prototype[name] = function(){
this.events.push([name]);
if(this._cbs[name]) this._cbs[name]();
};
} else if(EVENTS[name] === 1){
name = "on" + name;
CollectingHandler.prototype[name] = function(a){
this.events.push([name, a]);
if(this._cbs[name]) this._cbs[name](a);
};
} else if(EVENTS[name] === 2){
name = "on" + name;
CollectingHandler.prototype[name] = function(a, b){
this.events.push([name, a, b]);
if(this._cbs[name]) this._cbs[name](a, b);
};
} else {
throw Error("wrong number of arguments");
}
});
CollectingHandler.prototype.onreset = function(){
this.events = [];
if(this._cbs.onreset) this._cbs.onreset();
};
CollectingHandler.prototype.restart = function(){
if(this._cbs.onreset) this._cbs.onreset();
for(var i = 0, len = this.events.length; i < len; i++){
if(this._cbs[this.events[i][0]]){
var num = this.events[i].length;
if(num === 1){
this._cbs[this.events[i][0]]();
} else if(num === 2){
this._cbs[this.events[i][0]](this.events[i][1]);
} else {
this._cbs[this.events[i][0]](this.events[i][1], this.events[i][2]);
}
}
}
};

View File

@ -1,95 +0,0 @@
var index = require("./index.js"),
DomHandler = index.DomHandler,
DomUtils = index.DomUtils;
//TODO: make this a streamable handler
function FeedHandler(callback, options){
this.init(callback, options);
}
require("util").inherits(FeedHandler, DomHandler);
FeedHandler.prototype.init = DomHandler;
function getElements(what, where){
return DomUtils.getElementsByTagName(what, where, true);
}
function getOneElement(what, where){
return DomUtils.getElementsByTagName(what, where, true, 1)[0];
}
function fetch(what, where, recurse){
return DomUtils.getText(
DomUtils.getElementsByTagName(what, where, recurse, 1)
).trim();
}
function addConditionally(obj, prop, what, where, recurse){
var tmp = fetch(what, where, recurse);
if(tmp) obj[prop] = tmp;
}
var isValidFeed = function(value) {
return value === "rss" || value === "feed" || value === "rdf:RDF";
};
FeedHandler.prototype.onend = function() {
var feed = {},
feedRoot = getOneElement(isValidFeed, this.dom),
tmp, childs;
if(feedRoot){
if(feedRoot.name === "feed"){
childs = feedRoot.children;
feed.type = "atom";
addConditionally(feed, "id", "id", childs);
addConditionally(feed, "title", "title", childs);
if((tmp = getOneElement("link", childs)) && (tmp = tmp.attribs) && (tmp = tmp.href)) feed.link = tmp;
addConditionally(feed, "description", "subtitle", childs);
if((tmp = fetch("updated", childs))) feed.updated = new Date(tmp);
addConditionally(feed, "author", "email", childs, true);
feed.items = getElements("entry", childs).map(function(item){
var entry = {}, tmp;
item = item.children;
addConditionally(entry, "id", "id", item);
addConditionally(entry, "title", "title", item);
if((tmp = getOneElement("link", item)) && (tmp = tmp.attribs) && (tmp = tmp.href)) entry.link = tmp;
addConditionally(entry, "description", "summary", item);
if((tmp = fetch("updated", item))) entry.pubDate = new Date(tmp);
return entry;
});
} else {
childs = getOneElement("channel", feedRoot.children).children;
feed.type = feedRoot.name.substr(0, 3);
feed.id = "";
addConditionally(feed, "title", "title", childs);
addConditionally(feed, "link", "link", childs);
addConditionally(feed, "description", "description", childs);
if((tmp = fetch("lastBuildDate", childs))) feed.updated = new Date(tmp);
addConditionally(feed, "author", "managingEditor", childs, true);
feed.items = getElements("item", feedRoot.children).map(function(item){
var entry = {}, tmp;
item = item.children;
addConditionally(entry, "id", "guid", item);
addConditionally(entry, "title", "title", item);
addConditionally(entry, "link", "link", item);
addConditionally(entry, "description", "description", item);
if((tmp = fetch("pubDate", item))) entry.pubDate = new Date(tmp);
return entry;
});
}
}
this.dom = feed;
DomHandler.prototype._handleCallback.call(
this, feedRoot ? null : Error("couldn't find root of feed")
);
};
module.exports = FeedHandler;

View File

@ -1,337 +0,0 @@
var Tokenizer = require("./Tokenizer.js");
/*
Options:
xmlMode: Special behavior for script/style tags (true by default)
lowerCaseAttributeNames: call .toLowerCase for each attribute name (true if xmlMode is `false`)
lowerCaseTags: call .toLowerCase for each tag name (true if xmlMode is `false`)
*/
/*
Callbacks:
oncdataend,
oncdatastart,
onclosetag,
oncomment,
oncommentend,
onerror,
onopentag,
onprocessinginstruction,
onreset,
ontext
*/
var formTags = {
input: true,
option: true,
optgroup: true,
select: true,
button: true,
datalist: true,
textarea: true
};
var openImpliesClose = {
tr : { tr:true, th:true, td:true },
th : { th:true },
td : { thead:true, td:true },
body : { head:true, link:true, script:true },
li : { li:true },
p : { p:true },
select : formTags,
input : formTags,
output : formTags,
button : formTags,
datalist: formTags,
textarea: formTags,
option : { option:true },
optgroup: { optgroup:true }
};
var voidElements = {
__proto__: null,
area: true,
base: true,
basefont: true,
br: true,
col: true,
command: true,
embed: true,
frame: true,
hr: true,
img: true,
input: true,
isindex: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true,
//common self closing svg elements
path: true,
circle: true,
ellipse: true,
line: true,
rect: true,
use: true
};
var re_nameEnd = /\s|\//;
function Parser(cbs, options){
this._options = options || {};
this._cbs = cbs || {};
this._tagname = "";
this._attribname = "";
this._attribvalue = "";
this._attribs = null;
this._stack = [];
this.startIndex = 0;
this.endIndex = null;
this._lowerCaseTagNames = "lowerCaseTags" in this._options ?
!!this._options.lowerCaseTags :
!this._options.xmlMode;
this._lowerCaseAttributeNames = "lowerCaseAttributeNames" in this._options ?
!!this._options.lowerCaseAttributeNames :
!this._options.xmlMode;
this._tokenizer = new Tokenizer(this._options, this);
}
require("util").inherits(Parser, require("events").EventEmitter);
Parser.prototype._updatePosition = function(initialOffset){
if(this.endIndex === null){
if(this._tokenizer._sectionStart <= initialOffset){
this.startIndex = 0;
} else {
this.startIndex = this._tokenizer._sectionStart - initialOffset;
}
}
else this.startIndex = this.endIndex + 1;
this.endIndex = this._tokenizer._index;
};
//Tokenizer event handlers
Parser.prototype.ontext = function(data){
this._updatePosition(1);
this.endIndex--;
if(this._cbs.ontext) this._cbs.ontext(data);
};
Parser.prototype.onopentagname = function(name){
if(this._lowerCaseTagNames){
name = name.toLowerCase();
}
this._tagname = name;
if (!this._options.xmlMode && name in openImpliesClose) {
for(
var el;
(el = this._stack[this._stack.length-1]) in openImpliesClose[name];
this.onclosetag(el)
);
}
if(this._options.xmlMode || !(name in voidElements)){
this._stack.push(name);
}
if(this._cbs.onopentagname) this._cbs.onopentagname(name);
if(this._cbs.onopentag) this._attribs = {};
};
Parser.prototype.onopentagend = function(){
this._updatePosition(1);
if(this._attribs){
if(this._cbs.onopentag) this._cbs.onopentag(this._tagname, this._attribs);
this._attribs = null;
}
if(!this._options.xmlMode && this._cbs.onclosetag && this._tagname in voidElements){
this._cbs.onclosetag(this._tagname);
}
this._tagname = "";
};
Parser.prototype.onclosetag = function(name){
this._updatePosition(1);
if(this._lowerCaseTagNames){
name = name.toLowerCase();
}
if(this._stack.length && (!(name in voidElements) || this._options.xmlMode)){
var pos = this._stack.lastIndexOf(name);
if(pos !== -1){
if(this._cbs.onclosetag){
pos = this._stack.length - pos;
while(pos--) this._cbs.onclosetag(this._stack.pop());
}
else this._stack.length = pos;
} else if(name === "p" && !this._options.xmlMode){
this.onopentagname(name);
this._closeCurrentTag();
}
} else if(!this._options.xmlMode && (name === "br" || name === "p")){
this.onopentagname(name);
this._closeCurrentTag();
}
};
Parser.prototype.onselfclosingtag = function(){
if(this._options.xmlMode || this._options.recognizeSelfClosing){
this._closeCurrentTag();
} else {
this.onopentagend();
}
};
Parser.prototype._closeCurrentTag = function(){
var name = this._tagname;
this.onopentagend();
//self-closing tags will be on the top of the stack
//(cheaper check than in onclosetag)
if(this._stack[this._stack.length-1] === name){
if(this._cbs.onclosetag){
this._cbs.onclosetag(name);
}
this._stack.pop();
}
};
Parser.prototype.onattribname = function(name){
if(this._lowerCaseAttributeNames){
name = name.toLowerCase();
}
this._attribname = name;
};
Parser.prototype.onattribdata = function(value){
this._attribvalue += value;
};
Parser.prototype.onattribend = function(){
if(this._cbs.onattribute) this._cbs.onattribute(this._attribname, this._attribvalue);
if(
this._attribs &&
!Object.prototype.hasOwnProperty.call(this._attribs, this._attribname)
){
this._attribs[this._attribname] = this._attribvalue;
}
this._attribname = "";
this._attribvalue = "";
};
Parser.prototype._getInstructionName = function(value){
var idx = value.search(re_nameEnd),
name = idx < 0 ? value : value.substr(0, idx);
if(this._lowerCaseTagNames){
name = name.toLowerCase();
}
return name;
};
Parser.prototype.ondeclaration = function(value){
if(this._cbs.onprocessinginstruction){
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("!" + name, "!" + value);
}
};
Parser.prototype.onprocessinginstruction = function(value){
if(this._cbs.onprocessinginstruction){
var name = this._getInstructionName(value);
this._cbs.onprocessinginstruction("?" + name, "?" + value);
}
};
Parser.prototype.oncomment = function(value){
this._updatePosition(4);
if(this._cbs.oncomment) this._cbs.oncomment(value);
if(this._cbs.oncommentend) this._cbs.oncommentend();
};
Parser.prototype.oncdata = function(value){
this._updatePosition(1);
if(this._options.xmlMode || this._options.recognizeCDATA){
if(this._cbs.oncdatastart) this._cbs.oncdatastart();
if(this._cbs.ontext) this._cbs.ontext(value);
if(this._cbs.oncdataend) this._cbs.oncdataend();
} else {
this.oncomment("[CDATA[" + value + "]]");
}
};
Parser.prototype.onerror = function(err){
if(this._cbs.onerror) this._cbs.onerror(err);
};
Parser.prototype.onend = function(){
if(this._cbs.onclosetag){
for(
var i = this._stack.length;
i > 0;
this._cbs.onclosetag(this._stack[--i])
);
}
if(this._cbs.onend) this._cbs.onend();
};
//Resets the parser to a blank state, ready to parse a new HTML document
Parser.prototype.reset = function(){
if(this._cbs.onreset) this._cbs.onreset();
this._tokenizer.reset();
this._tagname = "";
this._attribname = "";
this._attribs = null;
this._stack = [];
};
//Parses a complete HTML document and pushes it to the handler
Parser.prototype.parseComplete = function(data){
this.reset();
this.end(data);
};
Parser.prototype.write = function(chunk){
this._tokenizer.write(chunk);
};
Parser.prototype.end = function(chunk){
this._tokenizer.end(chunk);
};
Parser.prototype.pause = function(){
this._tokenizer.pause();
};
Parser.prototype.resume = function(){
this._tokenizer.resume();
};
//alias for backwards compat
Parser.prototype.parseChunk = Parser.prototype.write;
Parser.prototype.done = Parser.prototype.end;
module.exports = Parser;

Some files were not shown because too many files have changed in this diff Show More