Skip to content

Commit 1083f82

Browse files
gibson042dmethvin
authored andcommittedFeb 28, 2013
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
1 parent 0618710 commit 1083f82

File tree

2 files changed

+151
-18
lines changed

2 files changed

+151
-18
lines changed
 

‎Gruntfile.js

+26-18
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module.exports = function( grunt ) {
2222
files: distpaths
2323
},
2424
selector: {
25-
destFile: "src/selector.js",
25+
destFile: "src/selector-sizzle.js",
2626
apiFile: "src/sizzle-jquery.js",
2727
srcFile: "src/sizzle/sizzle.js"
2828
},
@@ -39,10 +39,9 @@ module.exports = function( grunt ) {
3939
"src/queue.js",
4040
"src/attributes.js",
4141
"src/event.js",
42-
"src/selector.js",
42+
{ flag: "sizzle", src: "src/selector-sizzle.js", alt: "src/selector-native.js" },
4343
"src/traversing.js",
4444
"src/manipulation.js",
45-
4645
{ flag: "css", src: "src/css.js" },
4746
"src/serialize.js",
4847
{ flag: "event-alias", src: "src/event-alias.js" },
@@ -145,8 +144,7 @@ module.exports = function( grunt ) {
145144
});
146145
});
147146

148-
// Build src/selector.js
149-
grunt.registerTask( "selector", "Build src/selector.js", function() {
147+
grunt.registerTask( "selector", "Build Sizzle-based selector module", function() {
150148

151149
var cfg = grunt.config("selector"),
152150
name = cfg.destFile,
@@ -190,7 +188,7 @@ module.exports = function( grunt ) {
190188
// Rejoin the pieces
191189
compiled = parts.join("");
192190

193-
grunt.verbose.write("Injected sizzle-jquery.js into sizzle.js");
191+
grunt.verbose.writeln("Injected " + cfg.apiFile + " into " + cfg.srcFile);
194192

195193
// Write concatenated source to file, and ensure newline-only termination
196194
grunt.file.write( name, compiled.replace( /\x0d\x0a/g, "\x0a" ) );
@@ -328,37 +326,47 @@ module.exports = function( grunt ) {
328326
var flag = filepath.flag,
329327
specified = false,
330328
omit = false,
331-
message = "";
329+
messages = [];
332330

333331
if ( flag ) {
334332
if ( excluded[ flag ] !== undefined ) {
335-
message = ( "Excluding " + flag ).red;
333+
messages.push([
334+
( "Excluding " + flag ).red,
335+
( "(" + filepath.src + ")" ).grey
336+
]);
336337
specified = true;
337-
omit = true;
338-
} else {
339-
message = ( "Including " + flag ).green;
338+
omit = !filepath.alt;
339+
if ( !omit ) {
340+
flag += " alternate";
341+
filepath.src = filepath.alt;
342+
}
343+
}
344+
if ( excluded[ flag ] === undefined ) {
345+
messages.push([
346+
( "Including " + flag ).green,
347+
( "(" + filepath.src + ")" ).grey
348+
]);
340349

341350
// If this module was actually specified by the
342-
// builder, then st the flag to include it in the
351+
// builder, then set the flag to include it in the
343352
// output list
344353
if ( modules[ "+" + flag ] ) {
345354
specified = true;
346355
}
347356
}
348357

358+
filepath = filepath.src;
359+
349360
// Only display the inclusion/exclusion list when handling
350361
// an explicit list.
351362
//
352363
// Additionally, only display modules that have been specified
353364
// by the user
354365
if ( explicit && specified ) {
355-
grunt.log.writetableln([ 27, 30 ], [
356-
message,
357-
( "(" + filepath.src + ")").grey
358-
]);
366+
messages.forEach(function( message ) {
367+
grunt.log.writetableln( [ 27, 30 ], message );
368+
});
359369
}
360-
361-
filepath = filepath.src;
362370
}
363371

364372
if ( !omit ) {

‎src/selector-native.js

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
var selector_hasDuplicate,
2+
matches = docElem.matchesSelector ||
3+
docElem.mozMatchesSelector ||
4+
docElem.webkitMatchesSelector ||
5+
docElem.oMatchesSelector ||
6+
docElem.msMatchesSelector,
7+
selector_sortOrder = function( a, b ) {
8+
// Flag for duplicate removal
9+
if ( a === b ) {
10+
selector_hasDuplicate = true;
11+
return 0;
12+
}
13+
14+
var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
15+
16+
if ( compare ) {
17+
// Disconnected nodes
18+
if ( compare & 1 ) {
19+
20+
// Choose the first element that is related to our document
21+
if ( a === document || jQuery.contains(document, a) ) {
22+
return -1;
23+
}
24+
if ( b === document || jQuery.contains(document, b) ) {
25+
return 1;
26+
}
27+
28+
// Maintain original order
29+
return 0;
30+
}
31+
32+
return compare & 4 ? -1 : 1;
33+
}
34+
35+
// Not directly comparable, sort on existence of method
36+
return a.compareDocumentPosition ? -1 : 1;
37+
};
38+
39+
jQuery.extend({
40+
find: function( selector, context, results, seed ) {
41+
var elem,
42+
i = 0;
43+
44+
results = results || [];
45+
context = context || document;
46+
47+
if ( seed ) {
48+
while ( (elem = seed[i++]) ) {
49+
if ( jQuery.find.matchesSelector(elem, selector) ) {
50+
results.push( elem );
51+
}
52+
}
53+
} else {
54+
jQuery.merge( results, context.querySelectorAll(selector) );
55+
}
56+
57+
return results;
58+
},
59+
unique: function( results ) {
60+
var elem,
61+
duplicates = [],
62+
i = 0,
63+
j = 0;
64+
65+
selector_hasDuplicate = false;
66+
results.sort( selector_sortOrder );
67+
68+
if ( selector_hasDuplicate ) {
69+
while ( (elem = results[i++]) ) {
70+
if ( elem === results[ i ] ) {
71+
j = duplicates.push( i );
72+
}
73+
}
74+
while ( j-- ) {
75+
results.splice( duplicates[ j ], 1 );
76+
}
77+
}
78+
79+
return results;
80+
},
81+
text: function( elem ) {
82+
var node,
83+
ret = "",
84+
i = 0,
85+
nodeType = elem.nodeType;
86+
87+
if ( !nodeType ) {
88+
// If no nodeType, this is expected to be an array
89+
while ( (node = elem[i++]) ) {
90+
// Do not traverse comment nodes
91+
ret += jQuery.text( node );
92+
}
93+
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
94+
// Use textContent for elements
95+
return elem.textContent;
96+
} else if ( nodeType === 3 || nodeType === 4 ) {
97+
return elem.nodeValue;
98+
}
99+
// Do not include comment or processing instruction nodes
100+
101+
return ret;
102+
},
103+
contains: function( a, b ) {
104+
var adown = a.nodeType === 9 ? a.documentElement : a,
105+
bup = b && b.parentNode;
106+
return a === bup || !!( bup && bup.nodeType === 1 && adown.contains(bup) );
107+
},
108+
isXMLDoc: function( elem ) {
109+
return (elem.ownerDocument || elem).documentElement.nodeName !== "HTML";
110+
},
111+
expr: {
112+
match: {
113+
needsContext: /^[\x20\t\r\n\f]*[>+~]/
114+
}
115+
}
116+
});
117+
118+
jQuery.extend( jQuery.find, {
119+
matches: function( expr, elements ) {
120+
return jQuery.find( expr, null, null, elements );
121+
},
122+
matchesSelector: function( elem, expr ) {
123+
return matches.call( elem, expr );
124+
}
125+
});

0 commit comments

Comments
 (0)