Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix(jqLite): fix add/remove class in IE9 #9474

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/jqLite.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,20 +358,24 @@ function jqLiteHasClass(element, selector) {
}

function jqLiteRemoveClass(element, cssClasses) {
if (cssClasses && element.setAttribute) {
if (cssClasses && (element.setAttribute || msie === 9)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what we're really testing here is that the element is a DOM node --- IE9 has setAttribute (since IE8 actually) so under what conditions do we not have this?

var existingClasses = (" " +
((element.getAttribute && element.getAttribute('class')) ||
element.className || '') +
" ").replace(/[\n\t]/g, " ");

forEach(cssClasses.split(' '), function(cssClass) {
element.setAttribute('class', trim(
(" " + (element.getAttribute('class') || '') + " ")
.replace(/[\n\t]/g, " ")
.replace(" " + trim(cssClass) + " ", " "))
);
existingClasses = existingClasses.replace(" " + trim(cssClass) + " ", " ");
});

(msie === 9 && !(element instanceof SVGElement)) ? element.className = trim(existingClasses) :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does IE9 parse classes when the attribute is set for SVG elements but not for other elements? (I know className is an object in SVG, but it's weird that this is necessary at all). Would this break SVG class operations for IE9?

In either case, there is a lot of branching happening in this function, what if we just had two versions of the function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we just had two versions of the function?

Considered it; this would also make it easy to drop support for IE9 in the future. Let me put together an alternate PR and see what that looks like.

element.setAttribute('class', trim(existingClasses));
}
}

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) {
Expand All @@ -381,7 +385,8 @@ function jqLiteAddClass(element, cssClasses) {
}
});

element.setAttribute('class', trim(existingClasses));
(msie === 9 && !(element instanceof SVGElement)) ? element.className = trim(existingClasses) :
element.setAttribute('class', trim(existingClasses));
}
}

Expand Down
20 changes: 20 additions & 0 deletions test/jqLiteSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,15 @@ describe('jqLite', function() {
});


it('should allow adding of class in IE9', function() {
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);
expect(jqA[0].className).toBe('');
Expand Down Expand Up @@ -836,6 +845,17 @@ describe('jqLite', function() {
});


it('should allow removal of class in IE9', function() {
if (!(jqLite(a).setAttribute && jqLite(a).getAttribute)) return; // IE9 doesn't support node.setAttribute
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to http://msdn.microsoft.com/en-us/library/ie/ms536739(v=vs.85).aspx,

Windows Internet Explorer 8 and later. IE8 Standards mode enables several enhancements to the setAttribute, getAttribute, and removeAttribute methods that are not available when pages are displayed in earlier document modes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but besides that, jqLite(a) is gonna be a jQuery/jqLite object --- so it's not going to have getAttribute or setAttribute anyways, only attr()

var selector = jqLite([a, b]);
a.className = 'abc';
b.className = 'abc';
expect(selector.removeClass('abc')).toBe(selector);
expect(jqLite(a).hasClass('abc')).toBe(false);
expect(jqLite(b).hasClass('abc')).toBe(false);
});


it('should correctly remove middle class', function() {
var element = jqLite('<div class="foo bar baz"></div>');
expect(element.hasClass('bar')).toBe(true);
Expand Down