Skip to content

Commit 20aaed3

Browse files
committed
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
1 parent 56bb677 commit 20aaed3

File tree

2 files changed

+71
-29
lines changed

2 files changed

+71
-29
lines changed

src/attributes/classes.js

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@ define([
77

88
var rclass = /[\t\r\n\f]/g;
99

10+
function getClass( elem ) {
11+
return elem.getAttribute && elem.getAttribute( "class" ) || "";
12+
}
13+
1014
jQuery.fn.extend({
1115
addClass: function( value ) {
12-
var classes, elem, cur, clazz, j, finalValue,
16+
var classes, elem, cur, curValue, clazz, j, finalValue,
1317
proceed = typeof value === "string" && value,
1418
i = 0,
1519
len = this.length;
1620

1721
if ( jQuery.isFunction( value ) ) {
1822
return this.each(function( j ) {
19-
jQuery( this ).addClass( value.call( this, j, this.className ) );
23+
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
2024
});
2125
}
2226

@@ -26,10 +30,9 @@ jQuery.fn.extend({
2630

2731
for ( ; i < len; i++ ) {
2832
elem = this[ i ];
29-
cur = elem.nodeType === 1 && ( elem.className ?
30-
( " " + elem.className + " " ).replace( rclass, " " ) :
31-
" "
32-
);
33+
curValue = getClass( elem );
34+
cur = elem.nodeType === 1 &&
35+
( " " + curValue + " " ).replace( rclass, " " );
3336

3437
if ( cur ) {
3538
j = 0;
@@ -41,8 +44,8 @@ jQuery.fn.extend({
4144

4245
// only assign if different to avoid unneeded rendering.
4346
finalValue = jQuery.trim( cur );
44-
if ( elem.className !== finalValue ) {
45-
elem.className = finalValue;
47+
if ( curValue !== finalValue ) {
48+
elem.setAttribute( "class", finalValue );
4649
}
4750
}
4851
}
@@ -52,26 +55,26 @@ jQuery.fn.extend({
5255
},
5356

5457
removeClass: function( value ) {
55-
var classes, elem, cur, clazz, j, finalValue,
58+
var classes, elem, cur, curValue, clazz, j, finalValue,
5659
proceed = arguments.length === 0 || typeof value === "string" && value,
5760
i = 0,
5861
len = this.length;
5962

6063
if ( jQuery.isFunction( value ) ) {
6164
return this.each(function( j ) {
62-
jQuery( this ).removeClass( value.call( this, j, this.className ) );
65+
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
6366
});
6467
}
6568
if ( proceed ) {
6669
classes = ( value || "" ).match( rnotwhite ) || [];
6770

6871
for ( ; i < len; i++ ) {
6972
elem = this[ i ];
73+
curValue = getClass( elem );
74+
7075
// This expression is here for better compressibility (see addClass)
71-
cur = elem.nodeType === 1 && ( elem.className ?
72-
( " " + elem.className + " " ).replace( rclass, " " ) :
73-
""
74-
);
76+
cur = elem.nodeType === 1 &&
77+
( " " + curValue + " " ).replace( rclass, " " );
7578

7679
if ( cur ) {
7780
j = 0;
@@ -84,8 +87,8 @@ jQuery.fn.extend({
8487

8588
// Only assign if different to avoid unneeded rendering.
8689
finalValue = value ? jQuery.trim( cur ) : "";
87-
if ( elem.className !== finalValue ) {
88-
elem.className = finalValue;
90+
if ( curValue !== finalValue ) {
91+
elem.setAttribute( "class", finalValue );
8992
}
9093
}
9194
}
@@ -104,20 +107,24 @@ jQuery.fn.extend({
104107
if ( jQuery.isFunction( value ) ) {
105108
return this.each(function( i ) {
106109
jQuery( this ).toggleClass(
107-
value.call(this, i, this.className, stateVal), stateVal
110+
value.call( this, i, getClass( this ), stateVal ),
111+
stateVal
108112
);
109113
});
110114
}
111115

112116
return this.each(function() {
117+
var className, i, self, classNames;
118+
113119
if ( type === "string" ) {
120+
114121
// Toggle individual class names
115-
var className,
116-
i = 0,
117-
self = jQuery( this ),
118-
classNames = value.match( rnotwhite ) || [];
122+
i = 0;
123+
self = jQuery( this );
124+
classNames = value.match( rnotwhite ) || [];
125+
126+
while ( ( className = classNames[ i++ ] ) ) {
119127

120-
while ( (className = classNames[ i++ ]) ) {
121128
// Check each className given, space separated list
122129
if ( self.hasClass( className ) ) {
123130
self.removeClass( className );
@@ -128,18 +135,24 @@ jQuery.fn.extend({
128135

129136
// Toggle whole class name
130137
} else if ( value === undefined || type === "boolean" ) {
131-
if ( this.className ) {
138+
className = getClass( this );
139+
if ( className ) {
140+
132141
// store className if set
133-
dataPriv.set( this, "__className__", this.className );
142+
dataPriv.set( this, "__className__", className );
134143
}
135144

136145
// If the element has a class name or if we're passed `false`,
137146
// then remove the whole classname (if there was one, the above saved it).
138147
// Otherwise bring back whatever was previously saved (if anything),
139148
// falling back to the empty string if nothing was stored.
140-
this.className = this.className || value === false ?
141-
"" :
142-
dataPriv.get( this, "__className__" ) || "";
149+
if ( this.setAttribute ) {
150+
this.setAttribute( "class",
151+
className || value === false ?
152+
"" :
153+
dataPriv.get( this, "__className__" ) || ""
154+
);
155+
}
143156
}
144157
});
145158
},
@@ -150,8 +163,9 @@ jQuery.fn.extend({
150163
l = this.length;
151164
for ( ; i < l; i++ ) {
152165
if ( this[i].nodeType === 1 &&
153-
(" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
154-
166+
( " " + getClass( this[i] ) + " " ).replace( rclass, " " )
167+
.indexOf( className ) > -1
168+
) {
155169
return true;
156170
}
157171
}

test/unit/attributes.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,3 +1478,31 @@ test( "Insignificant white space returned for $(option).val() (#14858)", functio
14781478
val = jQuery( "<option> test </option>" ).val();
14791479
equal( val.length, 4, "insignificant white-space returned for value" );
14801480
});
1481+
1482+
test( "SVG class manipulation (gh-2199)", function() {
1483+
expect( 12 );
1484+
1485+
function createSVGElement( nodeName ) {
1486+
return document.createElementNS( "http://www.w3.org/2000/svg", nodeName );
1487+
}
1488+
1489+
jQuery.each([
1490+
"svg",
1491+
"rect",
1492+
"g"
1493+
], function() {
1494+
var elem = jQuery( createSVGElement( this ) );
1495+
1496+
elem.addClass( "awesome" );
1497+
ok( elem.hasClass( "awesome" ), "SVG element (" + this + ") has added class" );
1498+
1499+
elem.removeClass( "awesome" );
1500+
ok( !elem.hasClass( "awesome" ), "SVG element (" + this + ") removes the class" );
1501+
1502+
elem.toggleClass( "awesome" );
1503+
ok( elem.hasClass( "awesome" ), "SVG element (" + this + ") toggles the class on" );
1504+
1505+
elem.toggleClass( "awesome" );
1506+
ok( !elem.hasClass( "awesome" ), "SVG element (" + this + ") toggles the class off" );
1507+
});
1508+
});

0 commit comments

Comments
 (0)