@@ -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 ) {
@@ -188,18 +186,24 @@ jQuery.each({
jQuery.fn[ name ] = function( until, selector ) {
var ret = jQuery.map( this, fn, until );

if ( !runtil.test( name ) ) {
if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}

if ( selector && typeof selector === "string" ) {
ret = jQuery.filter( selector, ret );
}

ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
if ( this.length > 1 ) {
// Remove duplicates
if ( !guaranteedUnique[ name ] ) {
ret = jQuery.unique( ret );
}

if ( this.length > 1 && rparentsprev.test( name ) ) {
ret = ret.reverse();
// Reverse order for parents* and prev*
if ( name.charAt(0) === "p" ) {
ret = ret.reverse();
}
}

return this.pushStack( ret );
@@ -208,13 +212,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 ) {
@@ -244,36 +252,26 @@ 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;

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 ) {
return qualifier.call( elem, i, elem ) ? !not : not;
});

} else if ( qualifier.nodeType ) {
return jQuery.grep(elements, function( elem ) {
return ( elem === qualifier ) === keep;
return jQuery.grep( elements, function( elem ) {
return ( elem === qualifier ) !== not;
});

} else if ( typeof qualifier === "string" ) {
var 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 );
} else {
qualifier = jQuery.filter( qualifier, filtered );
qualifier = jQuery.filter( qualifier, elements );
}
}

return jQuery.grep(elements, function( elem ) {
return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
});
}
@@ -904,8 +904,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");
@@ -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>")
@@ -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() {
@@ -711,3 +730,15 @@ test("index(no arg) #10977", function() {
strictEqual ( jQuery( "#indextest li.zero" ).first().index() , 0, "No Argument Index Check" );
$list.remove();
});

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" );
});