Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improved caching and use subclassed Arrays for classList #1

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 53 additions & 45 deletions classList.js
@@ -1,62 +1,70 @@
(function () {
(function (global) {

if (typeof window.DOMTokenList !== 'undefined') return;
if (typeof global.DOMTokenList !== 'undefined') return;

var indexOf = [].indexOf,
slice = [].slice,
push = [].push,
splice = [].splice,
join = [].join;

function DOMTokenList(el) {
function DOMTokenList(el) {
this._element = el;
if (el.className != this.classCache) {
this._classCache = el.className;

var classes = this._classCache.split(' '),
i;
for (i = 0; i < classes.length; i++) {
push.call(this, classes[i]);
}
this.push.apply(this, el.className.split(regex));
// cache it if we can
if (mutationSupported) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need to cache anything? this._element.className is a perfectly good cache.

el._tokenList = this;
}
};

function setToClassName(el, classes) {
el.className = classes.join(' ');
}

DOMTokenList.prototype = {
add: function(token) {
push.call(this, token);
setToClassName(this._element, slice.call(this, 0));
},
contains: function(token) {
return indexOf.call(this, token) !== -1;
},
item: function(index) {
return this[index] || null;
},
remove: function(token) {
var i = indexOf.call(this, token);
splice.call(this, i, 1);
setToClassName(this._element, slice.call(this, 0));
},
toString: function() {
return join.call(this, ' ');
},
toggle: function(token) {
if (indexOf.call(this, token) === -1) {
this.add(token);
} else {
this.remove(token);
var
key
,regex = /\s+/g
,methods = {
add: function(token) {
this.push(token);
setToClassName(this._element, this);
},
contains: function(token) {
return this.indexOf(token) != -1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Breaks IE8.

},
item: function(index) {
return this[index] || null;
},
remove: function(token) {
this.splice(this.indexOf(token), 1);
setToClassName(this._element, this);
},
toString: function() {
return this.join(' ');
},
toggle: function(token) {
this[this.indexOf(token) == -1 ? 'add' : 'remove'](token);
}
}
};
,div = document.createElement('div')
,mutationSupported = false
;

window.DOMTokenList = DOMTokenList;
// IE doesn't maintain the length of subclassed arrays but we don't need it
DOMTokenList.prototype = new Array;
Copy link
Contributor

Choose a reason for hiding this comment

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

DOMTokenList is not an array. DOMTokenList only has a length property. This implementation is not spec conformant.


for (key in methods) {
DOMTokenList.prototype[key] = methods[key];
}
global.DOMTokenList = DOMTokenList;

Element.prototype.__defineGetter__('classList', function () {
return new DOMTokenList(this);
return this._tokenList || new DOMTokenList(this);
});

})();
// detech mutation support
div.addEventListener('DOMAttrModified'
Copy link
Contributor

Choose a reason for hiding this comment

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

Breaks IE8.

,function detectMutation() {
mutationSupported = true;
this.removeEventListener('DOMAttrModified', detectMutation, false);
}
,false
);
div.setAttribute('foo', 'bar');
div = null;
document.addEventListener('DOMAttrModified', function (e) { delete e.target._tokenList; }, false);
})(this);