Mapping components - Javascript
Accessing components in the DOM from Javascript using getElementById() is tedious, somewhat verbose, and does nothing to enhance the readability of the code. Generally there are two cases: finding global elements within the page, and finding members within (possibly repeated) components.
There are (of course) many ways to do this, but what I have settled on is using the ID attribute to identify global elements (what ID was meant for), and using the NAME attribute to identify members within a component. This use of the NAME attribute is exactly analogous to standard usage inside forms, just extended for use with non-form objects.
The code to build a map of global objects:
DOM.byId = function() {
var map = {};
DOM.asArray(arguments).apply(function(name){
var v = name.split('.');
var o = map;
while (1 < v.length) {
var s = v.shift();
o = o[s] = o[s] || {};
}
o[v[0]] = document.getElementById(name);
});
return map;
};
The code to build a map of a component:
DOM.byName = function(root) {
var map = {};
var walk = function(o) {
var name = o.getAttribute && o.getAttribute('name');
if (name) {
var v = name.split('.');
var m = map;
while (1 < v.length) {
var s = v.shift();
m = m[s] || (m[s] = {});
}
m[v[0]] = o;
}
for (o = o.firstChild; o; o = o.nextSibling) {
walk(o);
}
};
walk(root);
return map;
};
Usage is quite simple:
var named = DOM.byId(
'grid1',
'textWidth',
'textHeight'
);
var grid1 = DOM.byName(named.grid1);
Now named (by ID) global objects in the DOM can be later referred to in the Javascript code simply as named.grid1, named.textWidth, named.textHeight. Named objects within a component (by NAME) can be referred to as grid1.container, grid1.top.container, grid1.top.strip, (etc.).
Note that both DOM.byId() and DOM.byName() map IDs and NAMEs like "foo.bar" into a corresponding structure:
{ foo: { bar: reference to DOM element } }
Code in base.js.