Skip to content

Commit

Permalink
Attributes: add SVG class manipulation
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
timmywil committed May 12, 2015
1 parent cbd51c5 commit b5b0d72
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 33 deletions.
80 changes: 47 additions & 33 deletions src/attributes/classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) ) );
});
}

Expand All @@ -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;
Expand All @@ -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 );
}
}
}
Expand All @@ -51,26 +54,26 @@ 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 ) {
classes = ( value || "" ).match( rnotwhite ) || [];

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;
Expand All @@ -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 );
}
}
}
Expand All @@ -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 {
Expand All @@ -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__" ) || ""
);
}
}
});
},
Expand All @@ -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;
}
}
Expand Down
28 changes: 28 additions & 0 deletions test/unit/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -1476,3 +1476,31 @@ test( "Insignificant white space returned for $(option).val() (#14858)", functio
val = jQuery( "<option> test </option>" ).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" );
});
});

0 comments on commit b5b0d72

Please sign in to comment.