├── engines └── rhino │ ├── jars │ └── htmlparser-1.2.1.jar │ └── lib │ └── htmlparser.js ├── package.json ├── example.js ├── README.md └── lib └── sizzle.js /engines/rhino/jars/htmlparser-1.2.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subtleGradient/htmlparser/master/engines/rhino/jars/htmlparser-1.2.1.jar -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "htmlparser", 3 | "description": "An HTML parser", 4 | "keywords": ["html", "parser", "dom"], 5 | "author": "George Moschovitis (http://www.gmosx.com/)", 6 | "contributors": [], 7 | "lib": ["lib"], 8 | "jars": ["engines/rhino/jars/htmlparser-1.2.1.jar"], 9 | "lean": ["lib", "engines"] 10 | } 11 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var HTMLParser = require("htmlparser").HTMLParser, 2 | sizzle = require("sizzle").sizzle; 3 | 4 | var html = '
hello
second
', 5 | parser = new HTMLParser(), 6 | document = parser.parse(html), 7 | $ = sizzle(document); 8 | 9 | $("div").forEach(function(el) { 10 | print(el.innerHTML); 11 | }); 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HTML Parser 2 | =========== 3 | 4 | The HTML Parser is an implementation of the HTML5 parsing algorithm packaged for [CommonJS](http://www.commonjs.org). It is based on the excellent [Validator.nu HTML parser](http://about.validator.nu/htmlparser/). 5 | 6 | The parser is compatible with [Sizzle](http://sizzlejs.com/) which is included in the distribution for convenience. 7 | 8 | This is part of the [Nitro](http://www.nitrojs.org/) ecosystem of Web Application development tools. 9 | 10 | 11 | Usage 12 | ----- 13 | 14 | var HTMLParser = require("htmlparser").HTMLParser, 15 | sizzle = require("sizzle").sizzle; 16 | 17 | var html = '
hello
second
', 18 | parser = new HTMLParser(), 19 | document = parser.parse(html), 20 | $ = sizzle(document); 21 | 22 | $("div").forEach(function(el) { 23 | print(el.innerHTML); 24 | }); 25 | 26 | print(document.toHTML()); 27 | print(document); 28 | 29 | 30 | Credits 31 | ------- 32 | 33 | * George Moschovitis 34 | * Bryan Berry 35 | 36 | Java HTML Parser 37 | 38 | * Copyright (c) 2005, 2006, 2007 Henri Sivonen 39 | * Copyright (c) 2007-2008 Mozilla Foundation 40 | * Portions of comments Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA. 41 | 42 | 43 | License 44 | ------- 45 | 46 | Copyright (c) 2009-2010 George Moschovitis, [http://www.gmosx.com](http://www.gmosx.com) 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a copy 49 | of this software and associated documentation files (the "Software"), to 50 | deal in the Software without restriction, including without limitation the 51 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 52 | sell copies of the Software, and to permit persons to whom the Software is 53 | furnished to do so, subject to the following conditions: 54 | 55 | The above copyright notice and this permission notice shall be included in 56 | all copies or substantial portions of the Software. 57 | 58 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 59 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 60 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 61 | THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 62 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 63 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 64 | -------------------------------------------------------------------------------- /engines/rhino/lib/htmlparser.js: -------------------------------------------------------------------------------- 1 | var JInputSource = Packages.org.xml.sax.InputSource, 2 | JStringReader = Packages.java.io.StringReader, 3 | JHtmlDocumentBuilder = Packages.nu.validator.htmlparser.dom.HtmlDocumentBuilder; 4 | 5 | var jparser = new JHtmlDocumentBuilder(); 6 | 7 | var extend = function(Klass, Zuper) { 8 | Klass.prototype = Object.create(Zuper.prototype); 9 | Klass.prototype.constructor = Klass; 10 | } 11 | 12 | /** 13 | */ 14 | exports.parse = function(html, options) { 15 | return (new HTMLParser(options)).parse(html); 16 | } 17 | 18 | /** 19 | * A HTML5 parser. 20 | * 21 | * Based on: 22 | * http://about.validator.nu/htmlparser/ 23 | */ 24 | var HTMLParser = exports.HTMLParser = function(options) { 25 | } 26 | 27 | HTMLParser.prototype.parseRaw = function(html) { 28 | var source = new JInputSource(new JStringReader(html)); 29 | // source.setEncoding("UTF-8"); 30 | return jparser.parse(source); 31 | } 32 | 33 | HTMLParser.prototype.parse = function(html) { 34 | return new HTMLDocument(this.parseRaw(html)); 35 | } 36 | 37 | /** 38 | * An HTML Node. 39 | */ 40 | var HTMLNode = function(jnode) { 41 | this._raw = jnode; 42 | } 43 | 44 | HTMLNode.prototype.getChildNodes = function() { 45 | return _nodelistToArray(this._raw.getChildNodes()); 46 | } 47 | 48 | Object.defineProperty(HTMLNode.prototype, "nodeName", { 49 | get: function() { 50 | return String(this._raw.getNodeName()); 51 | } 52 | }); 53 | 54 | Object.defineProperty(HTMLNode.prototype, "nodeType", { 55 | get: function() { 56 | return Number(this._raw.getNodeType()); 57 | } 58 | }); 59 | 60 | Object.defineProperty(HTMLNode.prototype, "nodeValue", { 61 | get: function() { 62 | return String(this._raw.getNodeValue()); 63 | } 64 | }); 65 | 66 | HTMLNode.prototype.toString = function() { 67 | return this.nodeName; 68 | } 69 | 70 | var JDom2Sax = Packages.nu.validator.htmlparser.dom.Dom2Sax, 71 | JHtmlSerializer = Packages.nu.validator.htmlparser.sax.HtmlSerializer, 72 | JStringWriter = Packages.java.io.StringWriter; 73 | 74 | HTMLNode.prototype.toHTML = function() { 75 | var w = new JStringWriter(), 76 | s = new JHtmlSerializer(w); 77 | 78 | new JDom2Sax(s, s).parse(this._raw); 79 | 80 | return String(w.toString()); 81 | } 82 | 83 | /** 84 | * HTML Document. 85 | */ 86 | var HTMLDocument = function(jdocument) { 87 | this._raw = jdocument; 88 | } 89 | 90 | extend(HTMLDocument, HTMLNode); 91 | 92 | HTMLDocument.prototype.createElement = function(tagName) { 93 | return new HTMLElement(this._raw.createElement(tagName)); 94 | } 95 | 96 | HTMLDocument.prototype.createComment = function(data) { 97 | return new HTMLElement(this._raw.createComment(data)); 98 | } 99 | 100 | HTMLDocument.prototype.getElementById = function(id) { 101 | return new HTMLElement(this._raw.getElementById(id)); 102 | } 103 | 104 | HTMLDocument.prototype.getElementsByTagName = function(tagname) { 105 | return _nodelistToArray(this._raw.getElementsByTagName(tagname)); 106 | } 107 | 108 | Object.defineProperty(HTMLDocument.prototype, "documentElement", { 109 | get: function() { 110 | return new HTMLElement(this._raw.getDocumentElement()); 111 | } 112 | }); 113 | 114 | /** 115 | * HTML Element. 116 | */ 117 | var HTMLElement = function(jelement) { 118 | this._raw = jelement; 119 | } 120 | 121 | extend(HTMLElement, HTMLNode); 122 | 123 | HTMLElement.prototype.appendChild = function(newChild) { 124 | return new HTMLElement(this._raw.appendChild(newChild._raw)); 125 | } 126 | 127 | Object.defineProperty(HTMLElement.prototype, "checked", { 128 | get: function() { 129 | return this.hasAttribute("checked"); 130 | } 131 | }); 132 | 133 | Object.defineProperty(HTMLElement.prototype, "childNodes", { 134 | get: function() { 135 | return _nodelistToArray(this._raw.getChildNodes()); 136 | } 137 | }); 138 | 139 | Object.defineProperty(HTMLElement.prototype, "className", { 140 | get: function() { 141 | return this.getAttribute("class"); 142 | } 143 | }); 144 | 145 | HTMLElement.prototype.compareDocumentPosition = function(other) { 146 | return Number(this._raw.compareDocumentPosition(other)); 147 | } 148 | 149 | Object.defineProperty(HTMLElement.prototype, "disabled", { 150 | get: function() { 151 | return this.hasAttribute("disabled"); 152 | } 153 | }); 154 | 155 | Object.defineProperty(HTMLElement.prototype, "firstChild", { 156 | get: function() { 157 | var n = this._raw.getFirstChild(); 158 | return n ? new HTMLElement(n) : null; 159 | } 160 | }); 161 | 162 | HTMLElement.prototype.getAttribute = function(name) { 163 | return String(this._raw.getAttribute(name)); 164 | } 165 | 166 | HTMLElement.prototype.getAttributeNode = function(name) { 167 | var n = this._raw.getAttributeNode(name); 168 | return n ? new HTMLElement(n) : null; 169 | } 170 | 171 | HTMLElement.prototype.getElementsByTagName = function(tagname) { 172 | return _nodelistToArray(this._raw.getElementsByTagName(tagname)); 173 | } 174 | 175 | HTMLElement.prototype.hasAttribute = function(name) { 176 | return this._raw.hasAttribute(name); 177 | } 178 | 179 | Object.defineProperty(HTMLElement.prototype, "href", { 180 | get: function() { 181 | return String(this.getAttribute("href")); 182 | } 183 | }); 184 | 185 | Object.defineProperty(HTMLElement.prototype, "innerHTML", { 186 | get: function() { 187 | return String(this._raw.getTextContent()); 188 | }, 189 | set: function(content) { 190 | return String(this._raw.setTextContent(content)); 191 | } 192 | }); 193 | 194 | HTMLElement.prototype.insertBefore = function(newChild, refChild) { 195 | return new HTMLElement(this._raw.insertBefore(newChild._raw, refChild._raw)); 196 | } 197 | 198 | Object.defineProperty(HTMLElement.prototype, "lastChild", { 199 | get: function() { 200 | var n = this._raw.getLastChild(); 201 | return n ? new HTMLElement(n) : null; 202 | } 203 | }); 204 | 205 | Object.defineProperty(HTMLElement.prototype, "nextSibling", { 206 | get: function() { 207 | var n = this._raw.getNextSibling(); 208 | return n ? new HTMLElement(n) : null; 209 | } 210 | }); 211 | 212 | Object.defineProperty(HTMLElement.prototype, "ownerDocument", { 213 | get: function() { 214 | return new HTMLElement(this._raw.getOwnerDocument()); 215 | } 216 | }); 217 | 218 | Object.defineProperty(HTMLElement.prototype, "parentNode", { 219 | get: function() { 220 | var n = this._raw.getParentNode(); 221 | return n ? new HTMLElement(n) : null; 222 | } 223 | }); 224 | 225 | Object.defineProperty(HTMLElement.prototype, "previousSibling", { 226 | get: function() { 227 | var n = this._raw.getPreviousSibling(); 228 | return n ? new HTMLElement(n) : null; 229 | } 230 | }); 231 | 232 | HTMLElement.prototype.removeChild = function(oldChild) { 233 | return new HTMLElement(this._raw.removeChild(oldChild._raw)); 234 | } 235 | 236 | Object.defineProperty(HTMLElement.prototype, "selected", { 237 | get: function() { 238 | return this.hasAttribute("selected"); 239 | } 240 | }); 241 | 242 | Object.defineProperty(HTMLElement.prototype, "textContent", { 243 | get: function() { 244 | return String(this._raw.getTextContent()); 245 | } 246 | }); 247 | 248 | Object.defineProperty(HTMLElement.prototype, "type", { 249 | get: function() { 250 | return String(this.getAttribute("type")); 251 | } 252 | }); 253 | 254 | var _nodelistToArray = function(nodelist) { 255 | var arr = []; 256 | 257 | for (var i = 0; i < nodelist.getLength(); i++) { 258 | arr.push(new HTMLElement(nodelist.item(i))); 259 | } 260 | 261 | return arr; 262 | } 263 | -------------------------------------------------------------------------------- /lib/sizzle.js: -------------------------------------------------------------------------------- 1 | exports.sizzle = function(document) { 2 | var window = exports; 3 | 4 | 5 | /*! 6 | * Sizzle CSS Selector Engine - v1.0 7 | * Copyright 2009, The Dojo Foundation 8 | * Released under the MIT, BSD, and GPL Licenses. 9 | * More information: http://sizzlejs.com/ 10 | */ 11 | (function(){ 12 | 13 | var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, 14 | done = 0, 15 | toString = Object.prototype.toString, 16 | hasDuplicate = false, 17 | baseHasDuplicate = true; 18 | 19 | // Here we check if the JavaScript engine is using some sort of 20 | // optimization where it does not always call our comparision 21 | // function. If that is the case, discard the hasDuplicate value. 22 | // Thus far that includes Google Chrome. 23 | [0, 0].sort(function(){ 24 | baseHasDuplicate = false; 25 | return 0; 26 | }); 27 | 28 | var Sizzle = function(selector, context, results, seed) { 29 | results = results || []; 30 | var origContext = context = context || document; 31 | 32 | if ( context.nodeType !== 1 && context.nodeType !== 9 ) { 33 | return []; 34 | } 35 | 36 | if ( !selector || typeof selector !== "string" ) { 37 | return results; 38 | } 39 | 40 | var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), 41 | soFar = selector; 42 | 43 | // Reset the position of the chunker regexp (start from head) 44 | while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { 45 | soFar = m[3]; 46 | 47 | parts.push( m[1] ); 48 | 49 | if ( m[2] ) { 50 | extra = m[3]; 51 | break; 52 | } 53 | } 54 | 55 | if ( parts.length > 1 && origPOS.exec( selector ) ) { 56 | if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { 57 | set = posProcess( parts[0] + parts[1], context ); 58 | } else { 59 | set = Expr.relative[ parts[0] ] ? 60 | [ context ] : 61 | Sizzle( parts.shift(), context ); 62 | 63 | while ( parts.length ) { 64 | selector = parts.shift(); 65 | 66 | if ( Expr.relative[ selector ] ) 67 | selector += parts.shift(); 68 | 69 | set = posProcess( selector, set ); 70 | } 71 | } 72 | } else { 73 | // Take a shortcut and set the context if the root selector is an ID 74 | // (but not if it'll be faster if the inner selector is an ID) 75 | if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && 76 | Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { 77 | var ret = Sizzle.find( parts.shift(), context, contextXML ); 78 | context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; 79 | } 80 | 81 | if ( context ) { 82 | var ret = seed ? 83 | { expr: parts.pop(), set: makeArray(seed) } : 84 | Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); 85 | set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; 86 | 87 | if ( parts.length > 0 ) { 88 | checkSet = makeArray(set); 89 | } else { 90 | prune = false; 91 | } 92 | 93 | while ( parts.length ) { 94 | var cur = parts.pop(), pop = cur; 95 | 96 | if ( !Expr.relative[ cur ] ) { 97 | cur = ""; 98 | } else { 99 | pop = parts.pop(); 100 | } 101 | 102 | if ( pop == null ) { 103 | pop = context; 104 | } 105 | 106 | Expr.relative[ cur ]( checkSet, pop, contextXML ); 107 | } 108 | } else { 109 | checkSet = parts = []; 110 | } 111 | } 112 | 113 | if ( !checkSet ) { 114 | checkSet = set; 115 | } 116 | 117 | if ( !checkSet ) { 118 | throw "Syntax error, unrecognized expression: " + (cur || selector); 119 | } 120 | 121 | if ( toString.call(checkSet) === "[object Array]" ) { 122 | if ( !prune ) { 123 | results.push.apply( results, checkSet ); 124 | } else if ( context && context.nodeType === 1 ) { 125 | for ( var i = 0; checkSet[i] != null; i++ ) { 126 | if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { 127 | results.push( set[i] ); 128 | } 129 | } 130 | } else { 131 | for ( var i = 0; checkSet[i] != null; i++ ) { 132 | if ( checkSet[i] && checkSet[i].nodeType === 1 ) { 133 | results.push( set[i] ); 134 | } 135 | } 136 | } 137 | } else { 138 | makeArray( checkSet, results ); 139 | } 140 | 141 | if ( extra ) { 142 | Sizzle( extra, origContext, results, seed ); 143 | Sizzle.uniqueSort( results ); 144 | } 145 | 146 | return results; 147 | }; 148 | 149 | Sizzle.uniqueSort = function(results){ 150 | if ( sortOrder ) { 151 | hasDuplicate = baseHasDuplicate; 152 | results.sort(sortOrder); 153 | 154 | if ( hasDuplicate ) { 155 | for ( var i = 1; i < results.length; i++ ) { 156 | if ( results[i] === results[i-1] ) { 157 | results.splice(i--, 1); 158 | } 159 | } 160 | } 161 | } 162 | 163 | return results; 164 | }; 165 | 166 | Sizzle.matches = function(expr, set){ 167 | return Sizzle(expr, null, null, set); 168 | }; 169 | 170 | Sizzle.find = function(expr, context, isXML){ 171 | var set, match; 172 | 173 | if ( !expr ) { 174 | return []; 175 | } 176 | 177 | for ( var i = 0, l = Expr.order.length; i < l; i++ ) { 178 | var type = Expr.order[i], match; 179 | 180 | if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { 181 | var left = match[1]; 182 | match.splice(1,1); 183 | 184 | if ( left.substr( left.length - 1 ) !== "\\" ) { 185 | match[1] = (match[1] || "").replace(/\\/g, ""); 186 | set = Expr.find[ type ]( match, context, isXML ); 187 | if ( set != null ) { 188 | expr = expr.replace( Expr.match[ type ], "" ); 189 | break; 190 | } 191 | } 192 | } 193 | } 194 | 195 | if ( !set ) { 196 | set = context.getElementsByTagName("*"); 197 | } 198 | 199 | return {set: set, expr: expr}; 200 | }; 201 | 202 | Sizzle.filter = function(expr, set, inplace, not){ 203 | var old = expr, result = [], curLoop = set, match, anyFound, 204 | isXMLFilter = set && set[0] && isXML(set[0]); 205 | 206 | while ( expr && set.length ) { 207 | for ( var type in Expr.filter ) { 208 | if ( (match = Expr.match[ type ].exec( expr )) != null ) { 209 | var filter = Expr.filter[ type ], found, item; 210 | anyFound = false; 211 | 212 | if ( curLoop == result ) { 213 | result = []; 214 | } 215 | 216 | if ( Expr.preFilter[ type ] ) { 217 | match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); 218 | 219 | if ( !match ) { 220 | anyFound = found = true; 221 | } else if ( match === true ) { 222 | continue; 223 | } 224 | } 225 | 226 | if ( match ) { 227 | for ( var i = 0; (item = curLoop[i]) != null; i++ ) { 228 | if ( item ) { 229 | found = filter( item, match, i, curLoop ); 230 | var pass = not ^ !!found; 231 | 232 | if ( inplace && found != null ) { 233 | if ( pass ) { 234 | anyFound = true; 235 | } else { 236 | curLoop[i] = false; 237 | } 238 | } else if ( pass ) { 239 | result.push( item ); 240 | anyFound = true; 241 | } 242 | } 243 | } 244 | } 245 | 246 | if ( found !== undefined ) { 247 | if ( !inplace ) { 248 | curLoop = result; 249 | } 250 | 251 | expr = expr.replace( Expr.match[ type ], "" ); 252 | 253 | if ( !anyFound ) { 254 | return []; 255 | } 256 | 257 | break; 258 | } 259 | } 260 | } 261 | 262 | // Improper expression 263 | if ( expr == old ) { 264 | if ( anyFound == null ) { 265 | throw "Syntax error, unrecognized expression: " + expr; 266 | } else { 267 | break; 268 | } 269 | } 270 | 271 | old = expr; 272 | } 273 | 274 | return curLoop; 275 | }; 276 | 277 | var Expr = Sizzle.selectors = { 278 | order: [ "ID", "NAME", "TAG" ], 279 | match: { 280 | ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, 281 | CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, 282 | NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, 283 | ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, 284 | TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, 285 | CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, 286 | POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, 287 | PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ 288 | }, 289 | leftMatch: {}, 290 | attrMap: { 291 | "class": "className", 292 | "for": "htmlFor" 293 | }, 294 | attrHandle: { 295 | href: function(elem){ 296 | return elem.getAttribute("href"); 297 | } 298 | }, 299 | relative: { 300 | "+": function(checkSet, part, isXML){ 301 | var isPartStr = typeof part === "string", 302 | isTag = isPartStr && !/\W/.test(part), 303 | isPartStrNotTag = isPartStr && !isTag; 304 | 305 | if ( isTag && !isXML ) { 306 | part = part.toUpperCase(); 307 | } 308 | 309 | for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { 310 | if ( (elem = checkSet[i]) ) { 311 | while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} 312 | 313 | checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? 314 | elem || false : 315 | elem === part; 316 | } 317 | } 318 | 319 | if ( isPartStrNotTag ) { 320 | Sizzle.filter( part, checkSet, true ); 321 | } 322 | }, 323 | ">": function(checkSet, part, isXML){ 324 | var isPartStr = typeof part === "string"; 325 | 326 | if ( isPartStr && !/\W/.test(part) ) { 327 | part = isXML ? part : part.toUpperCase(); 328 | 329 | for ( var i = 0, l = checkSet.length; i < l; i++ ) { 330 | var elem = checkSet[i]; 331 | if ( elem ) { 332 | var parent = elem.parentNode; 333 | checkSet[i] = parent.nodeName === part ? parent : false; 334 | } 335 | } 336 | } else { 337 | for ( var i = 0, l = checkSet.length; i < l; i++ ) { 338 | var elem = checkSet[i]; 339 | if ( elem ) { 340 | checkSet[i] = isPartStr ? 341 | elem.parentNode : 342 | elem.parentNode === part; 343 | } 344 | } 345 | 346 | if ( isPartStr ) { 347 | Sizzle.filter( part, checkSet, true ); 348 | } 349 | } 350 | }, 351 | "": function(checkSet, part, isXML){ 352 | var doneName = done++, checkFn = dirCheck; 353 | 354 | if ( !/\W/.test(part) ) { 355 | var nodeCheck = part = isXML ? part : part.toUpperCase(); 356 | checkFn = dirNodeCheck; 357 | } 358 | 359 | checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); 360 | }, 361 | "~": function(checkSet, part, isXML){ 362 | var doneName = done++, checkFn = dirCheck; 363 | 364 | if ( typeof part === "string" && !/\W/.test(part) ) { 365 | var nodeCheck = part = isXML ? part : part.toUpperCase(); 366 | checkFn = dirNodeCheck; 367 | } 368 | 369 | checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); 370 | } 371 | }, 372 | find: { 373 | ID: function(match, context, isXML){ 374 | if ( typeof context.getElementById !== "undefined" && !isXML ) { 375 | var m = context.getElementById(match[1]); 376 | return m ? [m] : []; 377 | } 378 | }, 379 | NAME: function(match, context, isXML){ 380 | if ( typeof context.getElementsByName !== "undefined" ) { 381 | var ret = [], results = context.getElementsByName(match[1]); 382 | 383 | for ( var i = 0, l = results.length; i < l; i++ ) { 384 | if ( results[i].getAttribute("name") === match[1] ) { 385 | ret.push( results[i] ); 386 | } 387 | } 388 | 389 | return ret.length === 0 ? null : ret; 390 | } 391 | }, 392 | TAG: function(match, context){ 393 | return context.getElementsByTagName(match[1]); 394 | } 395 | }, 396 | preFilter: { 397 | CLASS: function(match, curLoop, inplace, result, not, isXML){ 398 | match = " " + match[1].replace(/\\/g, "") + " "; 399 | 400 | if ( isXML ) { 401 | return match; 402 | } 403 | 404 | for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { 405 | if ( elem ) { 406 | if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { 407 | if ( !inplace ) 408 | result.push( elem ); 409 | } else if ( inplace ) { 410 | curLoop[i] = false; 411 | } 412 | } 413 | } 414 | 415 | return false; 416 | }, 417 | ID: function(match){ 418 | return match[1].replace(/\\/g, ""); 419 | }, 420 | TAG: function(match, curLoop){ 421 | for ( var i = 0; curLoop[i] === false; i++ ){} 422 | return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); 423 | }, 424 | CHILD: function(match){ 425 | if ( match[1] == "nth" ) { 426 | // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' 427 | var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( 428 | match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || 429 | !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); 430 | 431 | // calculate the numbers (first)n+(last) including if they are negative 432 | match[2] = (test[1] + (test[2] || 1)) - 0; 433 | match[3] = test[3] - 0; 434 | } 435 | 436 | // TODO: Move to normal caching system 437 | match[0] = done++; 438 | 439 | return match; 440 | }, 441 | ATTR: function(match, curLoop, inplace, result, not, isXML){ 442 | var name = match[1].replace(/\\/g, ""); 443 | 444 | if ( !isXML && Expr.attrMap[name] ) { 445 | match[1] = Expr.attrMap[name]; 446 | } 447 | 448 | if ( match[2] === "~=" ) { 449 | match[4] = " " + match[4] + " "; 450 | } 451 | 452 | return match; 453 | }, 454 | PSEUDO: function(match, curLoop, inplace, result, not){ 455 | if ( match[1] === "not" ) { 456 | // If we're dealing with a complex expression, or a simple one 457 | if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { 458 | match[3] = Sizzle(match[3], null, null, curLoop); 459 | } else { 460 | var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); 461 | if ( !inplace ) { 462 | result.push.apply( result, ret ); 463 | } 464 | return false; 465 | } 466 | } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { 467 | return true; 468 | } 469 | 470 | return match; 471 | }, 472 | POS: function(match){ 473 | match.unshift( true ); 474 | return match; 475 | } 476 | }, 477 | filters: { 478 | enabled: function(elem){ 479 | return elem.disabled === false && elem.type !== "hidden"; 480 | }, 481 | disabled: function(elem){ 482 | return elem.disabled === true; 483 | }, 484 | checked: function(elem){ 485 | return elem.checked === true; 486 | }, 487 | selected: function(elem){ 488 | // Accessing this property makes selected-by-default 489 | // options in Safari work properly 490 | elem.parentNode.selectedIndex; 491 | return elem.selected === true; 492 | }, 493 | parent: function(elem){ 494 | return !!elem.firstChild; 495 | }, 496 | empty: function(elem){ 497 | return !elem.firstChild; 498 | }, 499 | has: function(elem, i, match){ 500 | return !!Sizzle( match[3], elem ).length; 501 | }, 502 | header: function(elem){ 503 | return /h\d/i.test( elem.nodeName ); 504 | }, 505 | text: function(elem){ 506 | return "text" === elem.type; 507 | }, 508 | radio: function(elem){ 509 | return "radio" === elem.type; 510 | }, 511 | checkbox: function(elem){ 512 | return "checkbox" === elem.type; 513 | }, 514 | file: function(elem){ 515 | return "file" === elem.type; 516 | }, 517 | password: function(elem){ 518 | return "password" === elem.type; 519 | }, 520 | submit: function(elem){ 521 | return "submit" === elem.type; 522 | }, 523 | image: function(elem){ 524 | return "image" === elem.type; 525 | }, 526 | reset: function(elem){ 527 | return "reset" === elem.type; 528 | }, 529 | button: function(elem){ 530 | return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; 531 | }, 532 | input: function(elem){ 533 | return /input|select|textarea|button/i.test(elem.nodeName); 534 | } 535 | }, 536 | setFilters: { 537 | first: function(elem, i){ 538 | return i === 0; 539 | }, 540 | last: function(elem, i, match, array){ 541 | return i === array.length - 1; 542 | }, 543 | even: function(elem, i){ 544 | return i % 2 === 0; 545 | }, 546 | odd: function(elem, i){ 547 | return i % 2 === 1; 548 | }, 549 | lt: function(elem, i, match){ 550 | return i < match[3] - 0; 551 | }, 552 | gt: function(elem, i, match){ 553 | return i > match[3] - 0; 554 | }, 555 | nth: function(elem, i, match){ 556 | return match[3] - 0 == i; 557 | }, 558 | eq: function(elem, i, match){ 559 | return match[3] - 0 == i; 560 | } 561 | }, 562 | filter: { 563 | PSEUDO: function(elem, match, i, array){ 564 | var name = match[1], filter = Expr.filters[ name ]; 565 | 566 | if ( filter ) { 567 | return filter( elem, i, match, array ); 568 | } else if ( name === "contains" ) { 569 | return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; 570 | } else if ( name === "not" ) { 571 | var not = match[3]; 572 | 573 | for ( var i = 0, l = not.length; i < l; i++ ) { 574 | if ( not[i] === elem ) { 575 | return false; 576 | } 577 | } 578 | 579 | return true; 580 | } 581 | }, 582 | CHILD: function(elem, match){ 583 | var type = match[1], node = elem; 584 | switch (type) { 585 | case 'only': 586 | case 'first': 587 | while ( (node = node.previousSibling) ) { 588 | if ( node.nodeType === 1 ) return false; 589 | } 590 | if ( type == 'first') return true; 591 | node = elem; 592 | case 'last': 593 | while ( (node = node.nextSibling) ) { 594 | if ( node.nodeType === 1 ) return false; 595 | } 596 | return true; 597 | case 'nth': 598 | var first = match[2], last = match[3]; 599 | 600 | if ( first == 1 && last == 0 ) { 601 | return true; 602 | } 603 | 604 | var doneName = match[0], 605 | parent = elem.parentNode; 606 | 607 | if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { 608 | var count = 0; 609 | for ( node = parent.firstChild; node; node = node.nextSibling ) { 610 | if ( node.nodeType === 1 ) { 611 | node.nodeIndex = ++count; 612 | } 613 | } 614 | parent.sizcache = doneName; 615 | } 616 | 617 | var diff = elem.nodeIndex - last; 618 | if ( first == 0 ) { 619 | return diff == 0; 620 | } else { 621 | return ( diff % first == 0 && diff / first >= 0 ); 622 | } 623 | } 624 | }, 625 | ID: function(elem, match){ 626 | return elem.nodeType === 1 && elem.getAttribute("id") === match; 627 | }, 628 | TAG: function(elem, match){ 629 | return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; 630 | }, 631 | CLASS: function(elem, match){ 632 | return (" " + (elem.className || elem.getAttribute("class")) + " ") 633 | .indexOf( match ) > -1; 634 | }, 635 | ATTR: function(elem, match){ 636 | var name = match[1], 637 | result = Expr.attrHandle[ name ] ? 638 | Expr.attrHandle[ name ]( elem ) : 639 | elem[ name ] != null ? 640 | elem[ name ] : 641 | elem.getAttribute( name ), 642 | value = result + "", 643 | type = match[2], 644 | check = match[4]; 645 | 646 | return result == null ? 647 | type === "!=" : 648 | type === "=" ? 649 | value === check : 650 | type === "*=" ? 651 | value.indexOf(check) >= 0 : 652 | type === "~=" ? 653 | (" " + value + " ").indexOf(check) >= 0 : 654 | !check ? 655 | value && result !== false : 656 | type === "!=" ? 657 | value != check : 658 | type === "^=" ? 659 | value.indexOf(check) === 0 : 660 | type === "$=" ? 661 | value.substr(value.length - check.length) === check : 662 | type === "|=" ? 663 | value === check || value.substr(0, check.length + 1) === check + "-" : 664 | false; 665 | }, 666 | POS: function(elem, match, i, array){ 667 | var name = match[2], filter = Expr.setFilters[ name ]; 668 | 669 | if ( filter ) { 670 | return filter( elem, i, match, array ); 671 | } 672 | } 673 | } 674 | }; 675 | 676 | var origPOS = Expr.match.POS; 677 | 678 | for ( var type in Expr.match ) { 679 | Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); 680 | Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); 681 | } 682 | 683 | var makeArray = function(array, results) { 684 | array = Array.prototype.slice.call( array, 0 ); 685 | 686 | if ( results ) { 687 | results.push.apply( results, array ); 688 | return results; 689 | } 690 | 691 | return array; 692 | }; 693 | 694 | // Perform a simple check to determine if the browser is capable of 695 | // converting a NodeList to an array using builtin methods. 696 | try { 697 | Array.prototype.slice.call( document.documentElement.childNodes, 0 ); 698 | 699 | // Provide a fallback method if it does not work 700 | } catch(e){ 701 | makeArray = function(array, results) { 702 | var ret = results || []; 703 | 704 | if ( toString.call(array) === "[object Array]" ) { 705 | Array.prototype.push.apply( ret, array ); 706 | } else { 707 | if ( typeof array.length === "number" ) { 708 | for ( var i = 0, l = array.length; i < l; i++ ) { 709 | ret.push( array[i] ); 710 | } 711 | } else { 712 | for ( var i = 0; array[i]; i++ ) { 713 | ret.push( array[i] ); 714 | } 715 | } 716 | } 717 | 718 | return ret; 719 | }; 720 | } 721 | 722 | var sortOrder; 723 | 724 | if ( document.documentElement.compareDocumentPosition ) { 725 | sortOrder = function( a, b ) { 726 | if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { 727 | if ( a == b ) { 728 | hasDuplicate = true; 729 | } 730 | return 0; 731 | } 732 | 733 | var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; 734 | if ( ret === 0 ) { 735 | hasDuplicate = true; 736 | } 737 | return ret; 738 | }; 739 | } else if ( "sourceIndex" in document.documentElement ) { 740 | sortOrder = function( a, b ) { 741 | if ( !a.sourceIndex || !b.sourceIndex ) { 742 | if ( a == b ) { 743 | hasDuplicate = true; 744 | } 745 | return 0; 746 | } 747 | 748 | var ret = a.sourceIndex - b.sourceIndex; 749 | if ( ret === 0 ) { 750 | hasDuplicate = true; 751 | } 752 | return ret; 753 | }; 754 | } else if ( document.createRange ) { 755 | sortOrder = function( a, b ) { 756 | if ( !a.ownerDocument || !b.ownerDocument ) { 757 | if ( a == b ) { 758 | hasDuplicate = true; 759 | } 760 | return 0; 761 | } 762 | 763 | var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); 764 | aRange.setStart(a, 0); 765 | aRange.setEnd(a, 0); 766 | bRange.setStart(b, 0); 767 | bRange.setEnd(b, 0); 768 | var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); 769 | if ( ret === 0 ) { 770 | hasDuplicate = true; 771 | } 772 | return ret; 773 | }; 774 | } 775 | 776 | // Check to see if the browser returns elements by name when 777 | // querying by getElementById (and provide a workaround) 778 | (function(){ 779 | // We're going to inject a fake input element with a specified name 780 | var form = document.createElement("div"), 781 | id = "script" + (new Date).getTime(); 782 | form.innerHTML = ""; 783 | 784 | // Inject it into the root element, check its status, and remove it quickly 785 | var root = document.documentElement; 786 | root.insertBefore( form, root.firstChild ); 787 | 788 | // The workaround has to do additional checks after a getElementById 789 | // Which slows things down for other browsers (hence the branching) 790 | if ( !!document.getElementById( id ) ) { 791 | Expr.find.ID = function(match, context, isXML){ 792 | if ( typeof context.getElementById !== "undefined" && !isXML ) { 793 | var m = context.getElementById(match[1]); 794 | return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; 795 | } 796 | }; 797 | 798 | Expr.filter.ID = function(elem, match){ 799 | var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); 800 | return elem.nodeType === 1 && node && node.nodeValue === match; 801 | }; 802 | } 803 | 804 | root.removeChild( form ); 805 | root = form = null; // release memory in IE 806 | })(); 807 | 808 | (function(){ 809 | // Check to see if the browser returns only elements 810 | // when doing getElementsByTagName("*") 811 | 812 | // Create a fake element 813 | var div = document.createElement("div"); 814 | div.appendChild( document.createComment("") ); 815 | 816 | // Make sure no comments are found 817 | if ( div.getElementsByTagName("*").length > 0 ) { 818 | Expr.find.TAG = function(match, context){ 819 | var results = context.getElementsByTagName(match[1]); 820 | 821 | // Filter out possible comments 822 | if ( match[1] === "*" ) { 823 | var tmp = []; 824 | 825 | for ( var i = 0; results[i]; i++ ) { 826 | if ( results[i].nodeType === 1 ) { 827 | tmp.push( results[i] ); 828 | } 829 | } 830 | 831 | results = tmp; 832 | } 833 | 834 | return results; 835 | }; 836 | } 837 | 838 | // Check to see if an attribute returns normalized href attributes 839 | div.innerHTML = ""; 840 | if (false) { 841 | // if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && 842 | // div.firstChild.getAttribute("href") !== "#" ) { 843 | Expr.attrHandle.href = function(elem){ 844 | return elem.getAttribute("href", 2); 845 | }; 846 | } 847 | 848 | div = null; // release memory in IE 849 | })(); 850 | 851 | if ( document.querySelectorAll ) (function(){ 852 | var oldSizzle = Sizzle, div = document.createElement("div"); 853 | div.innerHTML = "

"; 854 | 855 | // Safari can't handle uppercase or unicode characters when 856 | // in quirks mode. 857 | if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { 858 | return; 859 | } 860 | 861 | Sizzle = function(query, context, extra, seed){ 862 | context = context || document; 863 | 864 | // Only use querySelectorAll on non-XML documents 865 | // (ID selectors don't work in non-HTML documents) 866 | if ( !seed && context.nodeType === 9 && !isXML(context) ) { 867 | try { 868 | return makeArray( context.querySelectorAll(query), extra ); 869 | } catch(e){} 870 | } 871 | 872 | return oldSizzle(query, context, extra, seed); 873 | }; 874 | 875 | for ( var prop in oldSizzle ) { 876 | Sizzle[ prop ] = oldSizzle[ prop ]; 877 | } 878 | 879 | div = null; // release memory in IE 880 | })(); 881 | 882 | if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ 883 | var div = document.createElement("div"); 884 | div.innerHTML = "
"; 885 | 886 | // Opera can't find a second classname (in 9.6) 887 | if ( div.getElementsByClassName("e").length === 0 ) 888 | return; 889 | 890 | // Safari caches class attributes, doesn't catch changes (in 3.2) 891 | div.lastChild.className = "e"; 892 | 893 | if ( div.getElementsByClassName("e").length === 1 ) 894 | return; 895 | 896 | Expr.order.splice(1, 0, "CLASS"); 897 | Expr.find.CLASS = function(match, context, isXML) { 898 | if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { 899 | return context.getElementsByClassName(match[1]); 900 | } 901 | }; 902 | 903 | div = null; // release memory in IE 904 | })(); 905 | 906 | function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 907 | var sibDir = dir == "previousSibling" && !isXML; 908 | for ( var i = 0, l = checkSet.length; i < l; i++ ) { 909 | var elem = checkSet[i]; 910 | if ( elem ) { 911 | if ( sibDir && elem.nodeType === 1 ){ 912 | elem.sizcache = doneName; 913 | elem.sizset = i; 914 | } 915 | elem = elem[dir]; 916 | var match = false; 917 | 918 | while ( elem ) { 919 | if ( elem.sizcache === doneName ) { 920 | match = checkSet[elem.sizset]; 921 | break; 922 | } 923 | 924 | if ( elem.nodeType === 1 && !isXML ){ 925 | elem.sizcache = doneName; 926 | elem.sizset = i; 927 | } 928 | 929 | if ( elem.nodeName === cur ) { 930 | match = elem; 931 | break; 932 | } 933 | 934 | elem = elem[dir]; 935 | } 936 | 937 | checkSet[i] = match; 938 | } 939 | } 940 | } 941 | 942 | function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { 943 | var sibDir = dir == "previousSibling" && !isXML; 944 | for ( var i = 0, l = checkSet.length; i < l; i++ ) { 945 | var elem = checkSet[i]; 946 | if ( elem ) { 947 | if ( sibDir && elem.nodeType === 1 ) { 948 | elem.sizcache = doneName; 949 | elem.sizset = i; 950 | } 951 | elem = elem[dir]; 952 | var match = false; 953 | 954 | while ( elem ) { 955 | if ( elem.sizcache === doneName ) { 956 | match = checkSet[elem.sizset]; 957 | break; 958 | } 959 | 960 | if ( elem.nodeType === 1 ) { 961 | if ( !isXML ) { 962 | elem.sizcache = doneName; 963 | elem.sizset = i; 964 | } 965 | if ( typeof cur !== "string" ) { 966 | if ( elem === cur ) { 967 | match = true; 968 | break; 969 | } 970 | 971 | } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { 972 | match = elem; 973 | break; 974 | } 975 | } 976 | 977 | elem = elem[dir]; 978 | } 979 | 980 | checkSet[i] = match; 981 | } 982 | } 983 | } 984 | 985 | var contains = document.compareDocumentPosition ? function(a, b){ 986 | return a.compareDocumentPosition(b) & 16; 987 | } : function(a, b){ 988 | return a !== b && (a.contains ? a.contains(b) : true); 989 | }; 990 | 991 | var isXML = function(elem){ 992 | return elem.nodeType === 9; 993 | return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || 994 | !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; 995 | }; 996 | 997 | var posProcess = function(selector, context){ 998 | var tmpSet = [], later = "", match, 999 | root = context.nodeType ? [context] : context; 1000 | 1001 | // Position selectors must be done after the filter 1002 | // And so must :not(positional) so we move all PSEUDOs to the end 1003 | while ( (match = Expr.match.PSEUDO.exec( selector )) ) { 1004 | later += match[0]; 1005 | selector = selector.replace( Expr.match.PSEUDO, "" ); 1006 | } 1007 | 1008 | selector = Expr.relative[selector] ? selector + "*" : selector; 1009 | 1010 | for ( var i = 0, l = root.length; i < l; i++ ) { 1011 | Sizzle( selector, root[i], tmpSet ); 1012 | } 1013 | 1014 | return Sizzle.filter( later, tmpSet ); 1015 | }; 1016 | 1017 | // EXPOSE 1018 | window.Sizzle = Sizzle; 1019 | 1020 | })(); 1021 | 1022 | 1023 | 1024 | return exports.Sizzle; 1025 | } 1026 | --------------------------------------------------------------------------------