aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Gibson <richard.gibson@gmail.com>2013-03-26 21:20:27 -0400
committerRichard Gibson <richard.gibson@gmail.com>2013-04-05 00:37:36 -0400
commit5d1dfe747403c093cc0e837651dcf80027387fc6 (patch)
tree44cc433e2d2a3e496443128025983b39205c5822
parent6358da8aa32e7ed52da3af1a912bdd1a05863faf (diff)
downloadjquery-5d1dfe747403c093cc0e837651dcf80027387fc6.tar.gz
jquery-5d1dfe747403c093cc0e837651dcf80027387fc6.zip
Fix #13539: Utilize Sizzle hooks. Close gh-1215.
(cherry picked from commit 4ef516903e6e48bce388ca47c1ed88a447199fa1)
-rw-r--r--Gruntfile.js2
-rw-r--r--src/attributes.js125
m---------src/sizzle0
-rw-r--r--src/sizzle-jquery.js2
-rw-r--r--src/traversing.js57
-rw-r--r--test/unit/css.js4
-rw-r--r--test/unit/selector.js9
-rw-r--r--test/unit/traversing.js39
8 files changed, 133 insertions, 105 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 2317544ad..809ea3552 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -41,6 +41,7 @@ module.exports = function( grunt ) {
src: [
"src/intro.js",
"src/core.js",
+ { flag: "sizzle", src: "src/selector-sizzle.js", alt: "src/selector-native.js" },
"src/callbacks.js",
"src/deferred.js",
"src/support.js",
@@ -48,7 +49,6 @@ module.exports = function( grunt ) {
"src/queue.js",
"src/attributes.js",
"src/event.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" },
diff --git a/src/attributes.js b/src/attributes.js
index f116f8396..57257eba3 100644
--- a/src/attributes.js
+++ b/src/attributes.js
@@ -2,8 +2,7 @@ var nodeHook, boolHook,
rclass = /[\t\r\n]/g,
rreturn = /\r/g,
rfocusable = /^(?:input|select|textarea|button|object)$/i,
- rclickable = /^(?:a|area)$/i,
- rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i;
+ rclickable = /^(?:a|area)$/i;
jQuery.fn.extend({
attr: function( name, value ) {
@@ -291,7 +290,7 @@ jQuery.extend({
},
attr: function( elem, name, value ) {
- var ret, hooks, notxml,
+ var hooks, ret,
nType = elem.nodeType;
// don't get/set attributes on text, comment and attribute nodes
@@ -304,13 +303,12 @@ jQuery.extend({
return jQuery.prop( elem, name, value );
}
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
// All attributes are lowercase
// Grab necessary hook if one is defined
- if ( notxml ) {
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.boolean.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {
@@ -318,7 +316,7 @@ jQuery.extend({
if ( value === null ) {
jQuery.removeAttr( elem, name );
- } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
@@ -326,16 +324,11 @@ jQuery.extend({
return value;
}
- } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
-
- // In IE9+, Flash objects don't have .getAttribute (#12945)
- // Support: IE9+
- if ( typeof elem.getAttribute !== core_strundefined ) {
- ret = elem.getAttribute( name );
- }
+ ret = jQuery.find.attr( elem, name );
// Non-existent attributes return null, we normalize to undefined
return ret == null ?
@@ -354,8 +347,8 @@ jQuery.extend({
propName = jQuery.propFix[ name ] || name;
// Boolean attributes get special treatment (#10870)
- // Set corresponding property to false for boolean attributes
- if ( rboolean.test( name ) ) {
+ if ( jQuery.expr.match.boolean.test( name ) ) {
+ // Set corresponding property to false
elem[ propName ] = false;
}
@@ -382,18 +375,8 @@ jQuery.extend({
},
propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
"for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
+ "class": "className"
},
prop: function( elem, name, value ) {
@@ -448,13 +431,8 @@ jQuery.extend({
}
});
-// Hook for boolean attributes
+// Hooks for boolean attributes
boolHook = {
- get: function( elem, name ) {
- return elem.getAttribute( name ) !== null ?
- name.toLowerCase() :
- undefined;
- },
set: function( elem, value, name ) {
if ( value === false ) {
// Remove boolean attributes when set to false
@@ -465,32 +443,32 @@ boolHook = {
return name;
}
};
+jQuery.each( jQuery.expr.match.boolean.source.match( /\w+/g ), function( i, name ) {
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
-}
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
+ jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
+ var fn = jQuery.expr.attrHandle[ name ],
+ ret = isXML ?
+ undefined :
+ /* jshint eqeqeq: false */
+ // Temporarily disable this handler to check existence
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
+ getter( elem, name, isXML ) ?
+
+ name.toLowerCase() :
+ null;
+
+ // Restore handler
+ jQuery.expr.attrHandle[ name ] = fn;
+
+ return ret;
+ };
});
-// IE9/10 do not see a selected option inside an optgroup unless you access it
-// Support: IE9, IE10
+// Support: IE9+
+// Selectedness for an option in an optgroup can be inaccurate
if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;
if ( parent && parent.parentNode ) {
@@ -498,5 +476,38 @@ if ( !jQuery.support.optSelected ) {
}
return null;
}
- });
+ };
}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !jQuery.support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
diff --git a/src/sizzle b/src/sizzle
-Subproject a9ab22e770ab94c4c8b426e2f46f6ab91a19639
+Subproject cf19fa8dd6b7fda254bb3434f63d590845eaa7b
diff --git a/src/sizzle-jquery.js b/src/sizzle-jquery.js
index 2370b4493..fa3196543 100644
--- a/src/sizzle-jquery.js
+++ b/src/sizzle-jquery.js
@@ -1,5 +1,3 @@
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;
diff --git a/src/traversing.js b/src/traversing.js
index 81c1e5b57..a063a4612 100644
--- a/src/traversing.js
+++ b/src/traversing.js
@@ -1,6 +1,4 @@
-var runtil = /Until$/,
- rparentsprev = /^(?:parents|prev(?:Until|All))/,
- isSimple = /^.[^:#\[\.,]*$/,
+var isSimple = /^.[^:#\[\.,]*$/,
rneedsContext = jQuery.expr.match.needsContext,
// methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
@@ -52,11 +50,11 @@ jQuery.fn.extend({
},
not: function( selector ) {
- return this.pushStack( winnow(this, selector, false) );
+ return this.pushStack( winnow(this, selector || [], true) );
},
filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true) );
+ return this.pushStack( winnow(this, selector || [], false) );
},
is: function( selector ) {
@@ -186,7 +184,7 @@ jQuery.each({
jQuery.fn[ name ] = function( until, selector ) {
var matched = jQuery.map( this, fn, until );
- if ( !runtil.test( name ) ) {
+ if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}
@@ -195,11 +193,13 @@ jQuery.each({
}
if ( this.length > 1 ) {
+ // Remove duplicates
if ( !guaranteedUnique[ name ] ) {
jQuery.unique( matched );
}
- if ( rparentsprev.test( name ) ) {
+ // Reverse order for parents* and prev*
+ if ( name[ 0 ] === "p" ) {
matched.reverse();
}
}
@@ -210,13 +210,17 @@ jQuery.each({
jQuery.extend({
filter: function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
if ( not ) {
expr = ":not(" + expr + ")";
}
- return elems.length === 1 ?
- jQuery.find.matchesSelector( elems[ 0 ], expr ) ? [ elems[ 0 ] ] : [] :
- jQuery.find.matches( expr, elems );
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
},
dir: function( elem, dir, until ) {
@@ -248,40 +252,31 @@ jQuery.extend({
});
// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- var filtered;
-
+function winnow( elements, qualifier, not ) {
if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
});
+
}
if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem ) {
- return ( elem === qualifier ) === keep;
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
});
+
}
if ( typeof qualifier === "string" ) {
- filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
if ( isSimple.test( qualifier ) ) {
- return jQuery.filter( qualifier, filtered, !keep );
+ return jQuery.filter( qualifier, elements, not );
}
- qualifier = jQuery.filter( qualifier, filtered );
+ qualifier = jQuery.filter( qualifier, elements );
}
- return jQuery.grep(elements, function( elem ) {
- return ( core_indexOf.call( qualifier, elem ) >= 0 ) === keep;
+ return jQuery.grep( elements, function( elem ) {
+ return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
});
}
diff --git a/test/unit/css.js b/test/unit/css.js
index e8ce75b02..dc851f745 100644
--- a/test/unit/css.js
+++ b/test/unit/css.js
@@ -864,8 +864,8 @@ test( ":visible/:hidden selectors", function() {
ok( !jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is hidden" );
jQuery("#nothiddendiv").css({"display": "block"});
ok( jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is visible");
- ok( jQuery(window).is(":visible"), "Calling is(':visible') on window does not throw an error in IE.");
- ok( jQuery(document).is(":visible"), "Calling is(':visible') on document does not throw an error in IE.");
+ ok( jQuery(window).is(":visible") || true, "Calling is(':visible') on window does not throw an exception (#10267)");
+ ok( jQuery(document).is(":visible") || true, "Calling is(':visible') on document does not throw an exception (#10267)");
ok( jQuery("#nothiddendiv").is(":visible"), "Modifying CSS display: Assert element is visible");
jQuery("#nothiddendiv").css("display", "none");
diff --git a/test/unit/selector.js b/test/unit/selector.js
index 0cfba2834..440e7167b 100644
--- a/test/unit/selector.js
+++ b/test/unit/selector.js
@@ -31,17 +31,10 @@ test("class - jQuery only", function() {
});
test("attributes - jQuery only", function() {
- expect( 6 );
+ expect( 5 );
t( "Find elements with a tabindex attribute", "[tabindex]", ["listWithTabIndex", "foodWithNegativeTabIndex", "linkWithTabIndex", "linkWithNegativeTabIndex", "linkWithNoHrefWithTabIndex", "linkWithNoHrefWithNegativeTabIndex"] );
- // #12523
- deepEqual(
- jQuery.find( "[title]", null, null, jQuery("#qunit-fixture a").get().concat( document.createTextNode("") ) ),
- q("google"),
- "Text nodes fail attribute tests without exception"
- );
-
// #12600
ok(
jQuery("<select value='12600'><option value='option' selected='selected'></option><option value=''></option></select>")
diff --git a/test/unit/traversing.js b/test/unit/traversing.js
index 0e6439300..1060e7e40 100644
--- a/test/unit/traversing.js
+++ b/test/unit/traversing.js
@@ -78,10 +78,29 @@ test("is(String|undefined)", function() {
ok( jQuery("#en").is("[lang=\"de\"] , [lang=\"en\"]"), "Comma-separated; Check for lang attribute: Expect en or de" );
});
-test("is() against window|document (#10178)", function() {
- expect(2);
- ok( !jQuery(window).is("a"), "Checking is on a window does not throw an exception" );
- ok( !jQuery(document).is("a"), "Checking is on a document does not throw an exception" );
+test("is() against non-elements (#10178)", function() {
+ expect(14);
+
+ var label, i, test,
+ collection = jQuery( document ),
+ tests = [ "a", "*" ],
+ nonelements = {
+ text: document.createTextNode(""),
+ comment: document.createComment(""),
+ document: document,
+ window: window,
+ array: [],
+ "plain object": {},
+ "function": function() {}
+ };
+
+ for ( label in nonelements ) {
+ collection[ 0 ] = nonelements[ label ];
+ for ( i = 0; i < tests.length; i++ ) {
+ test = tests[ i ];
+ ok( !collection.is( test ), label + " does not match \"" + test + "\"" );
+ }
+ }
});
test("is(jQuery)", function() {
@@ -716,3 +735,15 @@ test("index(no arg) #10977", function() {
equal( jQuery( div ).index(), 0, "If jQuery#index called on element whose parent is fragment, it still should work correctly" );
});
+
+test("traversing non-elements with attribute filters (#12523)", function() {
+ expect(5);
+
+ var nonnodes = jQuery("#nonnodes").contents();
+
+ equal( nonnodes.filter("[id]").length, 1, ".filter" );
+ equal( nonnodes.find("[id]").length, 0, ".find" );
+ strictEqual( nonnodes.is("[id]"), true, ".is" );
+ deepEqual( nonnodes.closest("[id='nonnodes']").get(), q("nonnodes"), ".closest" );
+ deepEqual( nonnodes.parents("[id='nonnodes']").get(), q("nonnodes"), ".parents" );
+});