Updated title to better reflect what I'm trying to do.
In short, there are different constructors for different dom elements, and they don't seem to all share a common prototype. I'm looking for a way to add a function property to every DOM element by modifying these prototypes, but I'm not sure how to find them.
For example, I could do something like this:
function enhanceDom (tagNames, methods) {
var i=-1, tagName;
while (tagName=tagNames[++i]) {
var tag=document.createElement(tagName);
if (!(tag && tag.constructor)) continue;
for (var methodName in methods) {
tag.constructor.prototype[methodName]=methods[methodName];
}
}
}
var thingsToEnhance = ['a','abbr','acronym','address'/* on and on... */];
enhance(thingsToEnhance, {
doStuff : function(){
/* ... */
},
doOtherStuff : function(){
/* ... */
}
/* ... */
});
Of course, I'd like to do this without listing every single html element. Can anyone think of a better way?
(Original question follows)
Goal - make getElementsByClassName
work on any DOM node in any browser.
It's been done before (sort of), but here's my shot at it.
The question I have is, is there a good way to make this work with dynamically created elements? It seems that HTML DOM elements don't share a common predictable prototype where getElementsByClassName
could be added... Or am I missing something?
Here's what I've got so far (edit - updated per discussion).
(function(){
var fn = 'getElementsByClassName';
// var fn = 'gEBCN'; // test
if (typeof document[fn] != 'undefined') return;
// This is the part I want to get rid of...
// Can I add getByClass to a single prototype
// somewhere below Object and be done with it?
document[fn]=getByClass;
withDescendants(document, function (node) {
node[fn]=getByClass;
});
function withDescendants (node, callback, userdata) {
var nodes = node.getElementsByTagName('*'), i=-1;
while (node=nodes[++i]) {
callback(node, userdata);
}
return userdata;
}
function getByClass (className) {
return withDescendants(this, getMatches, {
query:new RegExp('(^|\\s+)' + className + '($|\\s+)'),
found:[]
}).found;
}
function getMatches (node, data) {
if (node.className && node.className.match(data.query)) {
data.found.push(node);
}
}
}());
It works well on content loaded before the script loads, but new dynamically-created elements won't get a getElementsByClassName
method. Any suggestions (besides setInterval, please)?
getElementsByTagName('*')
, I never thought of using that... in fact I could usee.getElementsByTagName('*')||e.all
and support everything back to IE4 I think :) – LabiategetElementById
. – LabiateclassName
, didn't realize it was so widely supported. – Labiate