-
Notifications
You must be signed in to change notification settings - Fork 27.4k
#5001: Fixes jqLite not correctly adding & removing classes in IE9 #5694
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -358,10 +358,11 @@ function jqLiteHasClass(element, selector) { | |
} | ||
|
||
function jqLiteRemoveClass(element, cssClasses) { | ||
if (cssClasses && element.setAttribute) { | ||
var setter = element.setAttribute ? function(value) { element.setAttribute('class', value); } : function(value) { element.className = value; }; | ||
if (cssClasses && (element.setAttribute || msie === 9)) { | ||
forEach(cssClasses.split(' '), function(cssClass) { | ||
element.setAttribute('class', trim( | ||
(" " + (element.getAttribute('class') || '') + " ") | ||
setter(trim( | ||
(" " + (element.getAttribute('class') || element.className || '') + " ") | ||
.replace(/[\n\t]/g, " ") | ||
.replace(" " + trim(cssClass) + " ", " ")) | ||
); | ||
|
@@ -371,7 +372,7 @@ function jqLiteRemoveClass(element, cssClasses) { | |
|
||
function jqLiteAddClass(element, cssClasses) { | ||
if (cssClasses && element.setAttribute) { | ||
var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') | ||
var existingClasses = (' ' + (element.getAttribute('class') || element.className || '') + ' ') | ||
.replace(/[\n\t]/g, " "); | ||
|
||
forEach(cssClasses.split(' '), function(cssClass) { | ||
|
@@ -381,7 +382,8 @@ function jqLiteAddClass(element, cssClasses) { | |
} | ||
}); | ||
|
||
element.setAttribute('class', trim(existingClasses)); | ||
(msie === 9 && !(element instanceof SVGElement)) ? element.className = trim(existingClasses) : | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, without that line, an SVG test breaks though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, well regardless, this change looks a bit weird, the logic is like
But the logic that would make sense is more like
This should be more performant than the instanceof check, and feature-checking is generally a better way to work than relying on browser sniffing. I would look at writing this like existingClasses = trim(existingClasses);
if (element.setAttribute) {
element.setAttribute('class', existingClasses);
} else if (isString(element.className)) {
element.className = existingClasses;
} This could be obfuscated/shrunk with clever operator use, but it basically comes down to feature detection rather than sniffing, and avoiding the prototype lookup There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright, I'll make the fix - definitely sounds better than what I wrote |
||
element.setAttribute('class', trim(existingClasses)); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -713,6 +713,14 @@ describe('jqLite', function() { | |
expect(jqLite(b).hasClass('abc')).toEqual(true); | ||
}); | ||
|
||
it('should allow adding of class in IE9', function() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought the issue was reported as only affecting nodes that had both Does this patch fix that? If so, that's probably what should be tested. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It actually turns out to be a broader issue - I'm not sure why it fails only in this particular case. |
||
if (!(jqLite(a).setAttribute && jqLite(a).getAttribute)) return; // IE9 doesn't support node.setAttribute | ||
var selector = jqLite([a, b]); | ||
expect(selector.addClass('abc')).toBe(selector); | ||
expect(jqLite(a).hasClass('abc')).toBe(true); | ||
expect(jqLite(b).hasClass('abc')).toBe(true); | ||
}); | ||
|
||
|
||
it('should ignore falsy values', function() { | ||
var jqA = jqLite(a); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could cache this:
This is slightly preferable (to me) compared with re-calculating and creating a new closure all the time. But someone else might have a word about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this change would break these unit tests:
jqLite class should properly do with SVG elements
$animate without animation should add and remove classes on SVG elements
ngAnimate should block and unblock transitions before the dom operation occurs
If I had to suspect, SVG elements might be a little special, and a higher level function which checks whether the element is an SVG element or regular element may be necessary here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, in order to maintain compat with jQuery, we should simply not care if it's an SVG element or not. jQuery seems to not distinguish between them, although there's no reason why they couldn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have spent a lot of time on trying to refactor & getting the unit tests to pass/remove SVG related unit tests - I am having a difficult time figuring out how to fix
ngAnimate should block and unblock transitions before the dom operation occurs
breaking. It would appear that$animate
is usingnode.setAttribute
implicitly somewhere while not callingelement.addClass
, although I'm not sure how - my first suspicion is withelement.attr
with jqLite, but it doesn't seem to be the culprit.