Skip to content

Instantly share code, notes, and snippets.

@krmgns
Last active October 28, 2020 01:25
Show Gist options
  • Save krmgns/c2ea7c49edf7b757fe9561ba37cb19ca to your computer and use it in GitHub Desktop.
Save krmgns/c2ea7c49edf7b757fe9561ba37cb19ca to your computer and use it in GitHub Desktop.
Polyfill: Element.prototype.classList for IE8/9, Safari.
/**
* Element.prototype.classList for IE8/9, Safari.
* @author Kerem Güneş <k-gun@mail.com>
* @copyright Released under the MIT License <https://opensource.org/licenses/MIT>
* @version 1.2
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
*/
;(function() {
// Helpers.
var trim = function(s) {
return s.replace(/^\s+|\s+$/g, '');
},
regExp = function(name) {
return new RegExp('(^|\\s+)'+ name +'(\\s+|$)');
},
forEach = function(list, fn, scope) {
for (var i = 0; i < list.length; i++) {
fn.call(scope, list[i]);
}
};
// Class list object with basic methods.
function ClassList(element) {
this.element = element;
}
ClassList.prototype = {
add: function() {
forEach(arguments, function(name) {
if (!this.contains(name)) {
this.element.className = trim(this.element.className +' '+ name);
}
}, this);
},
remove: function() {
forEach(arguments, function(name) {
this.element.className = trim(this.element.className.replace(regExp(name), ' '));
}, this);
},
toggle: function(name) {
return this.contains(name) ? (this.remove(name), false) : (this.add(name), true);
},
contains: function(name) {
return regExp(name).test(this.element.className);
},
item: function(i) {
return this.element.className.split(/\s+/)[i] || null;
},
// bonus
replace: function(oldName, newName) {
this.remove(oldName), this.add(newName);
}
};
// IE8/9, Safari
// Remove this if statements to override native classList.
if (!('classList' in Element.prototype)) {
// Use this if statement to override native classList that does not have for example replace() method.
// See browser compatibility: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList#Browser_compatibility.
// if (!('classList' in Element.prototype) ||
// !('classList' in Element.prototype && Element.prototype.classList.replace)) {
Object.defineProperty(Element.prototype, 'classList', {
get: function() {
return new ClassList(this);
}
});
}
// For others replace() support.
if (window.DOMTokenList && !DOMTokenList.prototype.replace) {
DOMTokenList.prototype.replace = ClassList.prototype.replace;
}
})();
@ballercat
Copy link

Please fix line 21. There should be no extra space if className is already empty.

@desjardinsm
Copy link

Also on line 28, for the remove(), if the class being removed is in the middle of two other classes rather than an end (and if classes are delimited by only a single space), it loses the space and the surrounding class names get combined into one.

@krmgns
Copy link
Author

krmgns commented Aug 22, 2017

@ballercat; even it is not worth to deal with empty class, fixed it.
@desjardinsm; that was a good catch, thank you, fixed.

And added item() and other trivial stuff, comments etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment