From b5b0d727740a2e5add2fa0daf0557e1e19a149cb Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 6 May 2015 13:30:16 -0700 Subject: [PATCH] Attributes: add SVG class manipulation - Note: support for SVG is limited in jQuery, but this is one area where the cost vs benefit ratio was acceptable. Fixes gh-2199 Close gh-2268 --- src/attributes/classes.js | 80 +++++++++++++++++++++++---------------- test/unit/attributes.js | 28 ++++++++++++++ 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/src/attributes/classes.js b/src/attributes/classes.js index 95146d25c..f08a1a142 100644 --- a/src/attributes/classes.js +++ b/src/attributes/classes.js @@ -6,16 +6,20 @@ define([ var rclass = /[\t\r\n\f]/g; +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + jQuery.fn.extend({ addClass: function( value ) { - var classes, elem, cur, clazz, j, finalValue, + var classes, elem, cur, curValue, clazz, j, finalValue, i = 0, len = this.length, proceed = typeof value === "string" && value; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { - jQuery( this ).addClass( value.call( this, j, this.className ) ); + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); }); } @@ -25,10 +29,9 @@ jQuery.fn.extend({ for ( ; i < len; i++ ) { elem = this[ i ]; - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - " " - ); + curValue = getClass( elem ); + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); if ( cur ) { j = 0; @@ -40,8 +43,8 @@ jQuery.fn.extend({ // only assign if different to avoid unneeded rendering. finalValue = jQuery.trim( cur ); - if ( elem.className !== finalValue ) { - elem.className = finalValue; + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); } } } @@ -51,14 +54,14 @@ jQuery.fn.extend({ }, removeClass: function( value ) { - var classes, elem, cur, clazz, j, finalValue, + var classes, elem, cur, curValue, clazz, j, finalValue, i = 0, len = this.length, proceed = arguments.length === 0 || typeof value === "string" && value; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { - jQuery( this ).removeClass( value.call( this, j, this.className ) ); + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); }); } if ( proceed ) { @@ -66,11 +69,11 @@ jQuery.fn.extend({ for ( ; i < len; i++ ) { elem = this[ i ]; + curValue = getClass( elem ); + // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - "" - ); + cur = elem.nodeType === 1 && + ( " " + curValue + " " ).replace( rclass, " " ); if ( cur ) { j = 0; @@ -83,8 +86,8 @@ jQuery.fn.extend({ // only assign if different to avoid unneeded rendering. finalValue = value ? jQuery.trim( cur ) : ""; - if ( elem.className !== finalValue ) { - elem.className = finalValue; + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); } } } @@ -103,21 +106,25 @@ jQuery.fn.extend({ if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( - value.call(this, i, this.className, stateVal), stateVal + value.call( this, i, getClass( this ), stateVal ), + stateVal ); }); } return this.each(function() { + var className, i, self, classNames; + if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - classNames = value.match( rnotwhite ) || []; - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnotwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list if ( self.hasClass( className ) ) { self.removeClass( className ); } else { @@ -126,19 +133,25 @@ jQuery.fn.extend({ } // Toggle whole class name - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + // store className if set - jQuery._data( this, "__className__", this.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. - this.className = this.className || value === false ? - "" : - jQuery._data( this, "__className__" ) || ""; + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + jQuery._data( this, "__className__" ) || "" + ); + } } }); }, @@ -149,8 +162,9 @@ jQuery.fn.extend({ l = this.length; for ( ; i < l; i++ ) { if ( this[i].nodeType === 1 && - (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - + ( " " + getClass( this[i] ) + " " ).replace( rclass, " " ) + .indexOf( className ) > -1 + ) { return true; } } diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 1e9c2fee2..022d4a8b3 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -1476,3 +1476,31 @@ test( "Insignificant white space returned for $(option).val() (#14858)", functio val = jQuery( "" ).val(); equal( val.length, 4, "insignificant white-space returned for value" ); }); + +test( "SVG class manipulation (gh-2199)", function() { + expect( 12 ); + + function createSVGElement( nodeName ) { + return document.createElementNS( "http://www.w3.org/2000/svg", nodeName ); + } + + jQuery.each([ + "svg", + "rect", + "g" + ], function() { + var elem = jQuery( createSVGElement( this ) ); + + elem.addClass( "awesome" ); + ok( elem.hasClass( "awesome" ), "SVG element (" + this + ") has added class" ); + + elem.removeClass( "awesome" ); + ok( !elem.hasClass( "awesome" ), "SVG element (" + this + ") removes the class" ); + + elem.toggleClass( "awesome" ); + ok( elem.hasClass( "awesome" ), "SVG element (" + this + ") toggles the class on" ); + + elem.toggleClass( "awesome" ); + ok( !elem.hasClass( "awesome" ), "SVG element (" + this + ") toggles the class off" ); + }); +}); -- 2.39.5