diff options
author | Richard Gibson <richard.gibson@gmail.com> | 2013-02-18 23:52:29 -0500 |
---|---|---|
committer | Dave Methvin <dave.methvin@gmail.com> | 2013-02-27 22:45:55 -0500 |
commit | 1083f82d1ee0c8f15a66be15e6184294a69d4420 (patch) | |
tree | 8e8571a87f4c4a3de06225442a674eeab6cd5420 | |
parent | 0618710913f41d7a7f4c095f0edda035e65a887d (diff) | |
download | jquery-1083f82d1ee0c8f15a66be15e6184294a69d4420.tar.gz jquery-1083f82d1ee0c8f15a66be15e6184294a69d4420.zip |
Fix #13434: native-API selector module
What's out:
* 6 KB
* attribute not equal selector
* positional selectors (:first; :eq(n); :odd; etc.)
* type selectors (:input; :checkbox; :button; etc.)
* state-based selectors (:animated; :visible; :hidden; etc.)
* :has(selector)
* custom selectors
* leading combinators (e.g., $collection.find("> *"))
* reliable functionality on XML fragments
* requiring all parts of a selector to match elements under context (e.g., $div.find("div > *") now matches children of $div)
* matching against non-elements
* reliable sorting of disconnected nodes
-rw-r--r-- | Gruntfile.js | 44 | ||||
-rw-r--r-- | src/selector-native.js | 125 |
2 files changed, 151 insertions, 18 deletions
diff --git a/Gruntfile.js b/Gruntfile.js index f202ac8fe..7ff43035e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,7 +22,7 @@ module.exports = function( grunt ) { files: distpaths }, selector: { - destFile: "src/selector.js", + destFile: "src/selector-sizzle.js", apiFile: "src/sizzle-jquery.js", srcFile: "src/sizzle/sizzle.js" }, @@ -39,10 +39,9 @@ module.exports = function( grunt ) { "src/queue.js", "src/attributes.js", "src/event.js", - "src/selector.js", + { flag: "sizzle", src: "src/selector-sizzle.js", alt: "src/selector-native.js" }, "src/traversing.js", "src/manipulation.js", - { flag: "css", src: "src/css.js" }, "src/serialize.js", { flag: "event-alias", src: "src/event-alias.js" }, @@ -145,8 +144,7 @@ module.exports = function( grunt ) { }); }); - // Build src/selector.js - grunt.registerTask( "selector", "Build src/selector.js", function() { + grunt.registerTask( "selector", "Build Sizzle-based selector module", function() { var cfg = grunt.config("selector"), name = cfg.destFile, @@ -190,7 +188,7 @@ module.exports = function( grunt ) { // Rejoin the pieces compiled = parts.join(""); - grunt.verbose.write("Injected sizzle-jquery.js into sizzle.js"); + grunt.verbose.writeln("Injected " + cfg.apiFile + " into " + cfg.srcFile); // Write concatenated source to file, and ensure newline-only termination grunt.file.write( name, compiled.replace( /\x0d\x0a/g, "\x0a" ) ); @@ -328,37 +326,47 @@ module.exports = function( grunt ) { var flag = filepath.flag, specified = false, omit = false, - message = ""; + messages = []; if ( flag ) { if ( excluded[ flag ] !== undefined ) { - message = ( "Excluding " + flag ).red; + messages.push([ + ( "Excluding " + flag ).red, + ( "(" + filepath.src + ")" ).grey + ]); specified = true; - omit = true; - } else { - message = ( "Including " + flag ).green; + omit = !filepath.alt; + if ( !omit ) { + flag += " alternate"; + filepath.src = filepath.alt; + } + } + if ( excluded[ flag ] === undefined ) { + messages.push([ + ( "Including " + flag ).green, + ( "(" + filepath.src + ")" ).grey + ]); // If this module was actually specified by the - // builder, then st the flag to include it in the + // builder, then set the flag to include it in the // output list if ( modules[ "+" + flag ] ) { specified = true; } } + filepath = filepath.src; + // Only display the inclusion/exclusion list when handling // an explicit list. // // Additionally, only display modules that have been specified // by the user if ( explicit && specified ) { - grunt.log.writetableln([ 27, 30 ], [ - message, - ( "(" + filepath.src + ")").grey - ]); + messages.forEach(function( message ) { + grunt.log.writetableln( [ 27, 30 ], message ); + }); } - - filepath = filepath.src; } if ( !omit ) { diff --git a/src/selector-native.js b/src/selector-native.js new file mode 100644 index 000000000..11bf32507 --- /dev/null +++ b/src/selector-native.js @@ -0,0 +1,125 @@ +var selector_hasDuplicate, + matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector, + selector_sortOrder = function( a, b ) { + // Flag for duplicate removal + if ( a === b ) { + selector_hasDuplicate = true; + return 0; + } + + var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b ); + + if ( compare ) { + // Disconnected nodes + if ( compare & 1 ) { + + // Choose the first element that is related to our document + if ( a === document || jQuery.contains(document, a) ) { + return -1; + } + if ( b === document || jQuery.contains(document, b) ) { + return 1; + } + + // Maintain original order + return 0; + } + + return compare & 4 ? -1 : 1; + } + + // Not directly comparable, sort on existence of method + return a.compareDocumentPosition ? -1 : 1; + }; + +jQuery.extend({ + find: function( selector, context, results, seed ) { + var elem, + i = 0; + + results = results || []; + context = context || document; + + if ( seed ) { + while ( (elem = seed[i++]) ) { + if ( jQuery.find.matchesSelector(elem, selector) ) { + results.push( elem ); + } + } + } else { + jQuery.merge( results, context.querySelectorAll(selector) ); + } + + return results; + }, + unique: function( results ) { + var elem, + duplicates = [], + i = 0, + j = 0; + + selector_hasDuplicate = false; + results.sort( selector_sortOrder ); + + if ( selector_hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; + }, + text: function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += jQuery.text( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + return elem.textContent; + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; + }, + contains: function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && adown.contains(bup) ); + }, + isXMLDoc: function( elem ) { + return (elem.ownerDocument || elem).documentElement.nodeName !== "HTML"; + }, + expr: { + match: { + needsContext: /^[\x20\t\r\n\f]*[>+~]/ + } + } +}); + +jQuery.extend( jQuery.find, { + matches: function( expr, elements ) { + return jQuery.find( expr, null, null, elements ); + }, + matchesSelector: function( elem, expr ) { + return matches.call( elem, expr ); + } +}); |