aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>2022-01-24 18:56:49 +0100
committerGitHub <noreply@github.com>2022-01-24 18:56:49 +0100
commita338b407f2479f82df40635055effc163835183f (patch)
treebe2a2f2b68d74a716388ea0027ff4083e000bfc9
parent9c6f64c7b51d50e334ef1183e2937ad77c0a68b0 (diff)
downloadjquery-a338b407f2479f82df40635055effc163835183f.tar.gz
jquery-a338b407f2479f82df40635055effc163835183f.zip
CSS: Skip falsy values in `addClass( array )`, compress code
This change makes jQuery skip falsy values in `addClass( array )` & `removeClass( array )` instead of stopping iteration when the first falsy value is detected. This makes code like: ```js elem.addClass( [ "a", "", "b" ] ); ``` add both the `a` & `b` classes. The code was also optimized for size a bit so it doesn't increase the minified gzipped size. Fixes gh-4998 Closes gh-5003
-rw-r--r--src/attributes/classes.js84
-rw-r--r--test/unit/attributes.js38
2 files changed, 82 insertions, 40 deletions
diff --git a/src/attributes/classes.js b/src/attributes/classes.js
index 796fbcc80..5e64ea2ae 100644
--- a/src/attributes/classes.js
+++ b/src/attributes/classes.js
@@ -20,8 +20,7 @@ function classesToArray( value ) {
jQuery.fn.extend( {
addClass: function( value ) {
- var classes, elem, cur, curValue, clazz, j, finalValue,
- i = 0;
+ var classNames, cur, curValue, className, i, finalValue;
if ( typeof value === "function" ) {
return this.each( function( j ) {
@@ -29,36 +28,35 @@ jQuery.fn.extend( {
} );
}
- classes = classesToArray( value );
+ classNames = classesToArray( value );
- if ( classes.length ) {
- while ( ( elem = this[ i++ ] ) ) {
- curValue = getClass( elem );
- cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+ if ( classNames.length ) {
+ return this.each( function() {
+ curValue = getClass( this );
+ cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
- j = 0;
- while ( ( clazz = classes[ j++ ] ) ) {
- if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
- cur += clazz + " ";
+ for ( i = 0; i < classNames.length; i++ ) {
+ className = classNames[ i ];
+ if ( cur.indexOf( " " + className + " " ) < 0 ) {
+ cur += className + " ";
}
}
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
- elem.setAttribute( "class", finalValue );
+ this.setAttribute( "class", finalValue );
}
}
- }
+ } );
}
return this;
},
removeClass: function( value ) {
- var classes, elem, cur, curValue, clazz, j, finalValue,
- i = 0;
+ var classNames, cur, curValue, className, i, finalValue;
if ( typeof value === "function" ) {
return this.each( function( j ) {
@@ -70,38 +68,40 @@ jQuery.fn.extend( {
return this.attr( "class", "" );
}
- classes = classesToArray( value );
+ classNames = classesToArray( value );
- if ( classes.length ) {
- while ( ( elem = this[ i++ ] ) ) {
- curValue = getClass( elem );
+ if ( classNames.length ) {
+ return this.each( function() {
+ curValue = getClass( this );
// This expression is here for better compressibility (see addClass)
- cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+ cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
- j = 0;
- while ( ( clazz = classes[ j++ ] ) ) {
+ for ( i = 0; i < classNames.length; i++ ) {
+ className = classNames[ i ];
// Remove *all* instances
- while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
- cur = cur.replace( " " + clazz + " ", " " );
+ while ( cur.indexOf( " " + className + " " ) > -1 ) {
+ cur = cur.replace( " " + className + " ", " " );
}
}
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
- elem.setAttribute( "class", finalValue );
+ this.setAttribute( "class", finalValue );
}
}
- }
+ } );
}
return this;
},
toggleClass: function( value, stateVal ) {
+ var classNames, className, i, self;
+
if ( typeof value === "function" ) {
return this.each( function( i ) {
jQuery( this ).toggleClass(
@@ -115,24 +115,28 @@ jQuery.fn.extend( {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
- return this.each( function() {
- var className, i, self, classNames;
+ classNames = classesToArray( value );
- // Toggle individual class names
- i = 0;
- self = jQuery( this );
- classNames = classesToArray( value );
+ if ( classNames.length ) {
+ return this.each( function() {
- while ( ( className = classNames[ i++ ] ) ) {
+ // Toggle individual class names
+ self = jQuery( this );
- // Check each className given, space separated list
- if ( self.hasClass( className ) ) {
- self.removeClass( className );
- } else {
- self.addClass( className );
+ for ( i = 0; i < classNames.length; i++ ) {
+ className = classNames[ i ];
+
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
}
- }
- } );
+ } );
+ }
+
+ return this;
},
hasClass: function( selector ) {
diff --git a/test/unit/attributes.js b/test/unit/attributes.js
index 98fae06c7..5f2418c7e 100644
--- a/test/unit/attributes.js
+++ b/test/unit/attributes.js
@@ -1644,6 +1644,44 @@ QUnit.test( "addClass, removeClass, hasClass on elements with classes with non-H
testMatches();
} );
+( function() {
+ var rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
+
+ function expectClasses( assert, elem, classes ) {
+ var actualClassesSorted = ( elem.attr( "class" ).match( rnothtmlwhite ) || [] )
+ .sort().join( " " );
+ var classesSorted = classes.slice()
+ .sort().join( " " );
+ assert.equal( actualClassesSorted, classesSorted, "Expected classes present" );
+ }
+
+ QUnit.test( "addClass on arrays with falsy elements (gh-4998)", function( assert ) {
+ assert.expect( 3 );
+
+ var elem = jQuery( "<div class='a'></div>" );
+
+ elem.addClass( [ "b", "", "c" ] );
+ expectClasses( assert, elem, [ "a", "b", "c" ] );
+ elem.addClass( [ "", "d" ] );
+ expectClasses( assert, elem, [ "a", "b", "c", "d" ] );
+ elem.addClass( [ "e", "" ] );
+ expectClasses( assert, elem, [ "a", "b", "c", "d", "e" ] );
+ } );
+
+ QUnit.test( "removeClass on arrays with falsy elements (gh-4998)", function( assert ) {
+ assert.expect( 3 );
+
+ var elem = jQuery( "<div class='a b c d e'></div>" );
+
+ elem.removeClass( [ "e", "" ] );
+ expectClasses( assert, elem, [ "a", "b", "c", "d" ] );
+ elem.removeClass( [ "", "d" ] );
+ expectClasses( assert, elem, [ "a", "b", "c" ] );
+ elem.removeClass( [ "b", "", "c" ] );
+ expectClasses( assert, elem, [ "a" ] );
+ } );
+} )();
+
QUnit.test( "contents().hasClass() returns correct values", function( assert ) {
assert.expect( 2 );