diff --git a/src/attributes.js b/src/attributes.js index 24514db2..612a28a6 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -1,5 +1,6 @@ var oldRemoveAttr = jQuery.fn.removeAttr, + oldToggleClass = jQuery.fn.toggleClass, rmatchNonSpace = /\S+/g; jQuery.fn.removeAttr = function( name ) { @@ -14,3 +15,34 @@ jQuery.fn.removeAttr = function( name ) { return oldRemoveAttr.apply( this, arguments ); }; + +jQuery.fn.toggleClass = function( state ) { + + // Only deprecating no-args or single boolean arg + if ( state !== undefined && typeof state !== "boolean" ) { + return oldToggleClass.apply( this, arguments ); + } + + migrateWarn( "jQuery.fn.toggleClass( boolean ) is deprecated" ); + + // Toggle entire class name of each element + return this.each( function() { + var className = this.getAttribute && this.getAttribute( "class" ) || ""; + + if ( className ) { + jQuery.data( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || state === false ? + "" : + jQuery.data( this, "__className__" ) || "" + ); + } + } ); +}; diff --git a/test/attributes.js b/test/attributes.js index 2018f28d..90810f22 100644 --- a/test/attributes.js +++ b/test/attributes.js @@ -41,3 +41,47 @@ QUnit.test( ".removeAttr( boolean attribute )", function( assert ) { } ); } ); + +QUnit.test( ".toggleClass( boolean )", function( assert ) { + assert.expect( 14 ); + + var e = jQuery( "
" ).appendTo( "#qunit-fixture" ); + + expectWarning( "toggling initially empty class", function() { + e.toggleClass( true ); + assert.equal( e[ 0 ].className, "", "Assert class is empty (data was empty)" ); + } ); + + expectNoWarning( ".toggleClass( string ) not full className", function() { + e.attr( "class", "" ); + e.toggleClass( "classy" ); + assert.equal( e.attr( "class" ), "classy", "class was toggle-set" ); + e.toggleClass( "classy", false ); + assert.equal( e.attr( "class" ), "", "class was toggle-removed" ); + } ); + + expectWarning( ".toggleClass() save and clear", 1, function() { + e.addClass( "testD testE" ); + assert.ok( e.is( ".testD.testE" ), "Assert class present" ); + e.toggleClass(); + assert.ok( !e.is( ".testD.testE" ), "Assert class not present" ); + + // N.B.: Store should have "testD testE" now, next test will assert that + } ); + + expectWarning( ".toggleClass() restore", 1, function() { + e.toggleClass(); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + } ); + + expectWarning( ".toggleClass( boolean )", 1, function() { + e.toggleClass( false ); + assert.ok( !e.is( ".testD.testE" ), "Assert class not present" ); + e.toggleClass( true ); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + e.toggleClass(); + e.toggleClass( false ); + e.toggleClass(); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + } ); +} ); diff --git a/warnings.md b/warnings.md index 8e1c105f..d5ad7c49 100644 --- a/warnings.md +++ b/warnings.md @@ -166,3 +166,9 @@ See jQuery-ui [commit](https://github.com/jquery/jquery-ui/commit/c0093b599fcd58 **Cause:** The standard way to add new custom selectors through jQuery is `jQuery.expr.pseudos`. These two other aliases are deprecated, although they still work as of jQuery 3.0. **Solution:** Rename any of the older usage to `jQuery.expr.pseudos`. The functionality is identical. + +### JQMIGRATE: jQuery.fn.toggleClass( [ boolean ] ) is deprecated + +**Cause:** Calling `.toggleClass()` with no arguments, or with a single Boolean `true` or `false` argument, has been deprecated. Its behavior was poorly documented, but essentially the method saved away the current `class` value in a data item when the class was removed and restored the saved value when it was toggled back. If you do not believe you are specificially trying to use this form of the method, it is possible you are accidentally doing so via an inadvertent undefined value, as `.toggleClass( undefined )` toggles all classes. + +**Solution:** If this functionality is still needed, save the current full `.attr( "class" )` value in a data item and restore it when required.