There's one big problem with XUL applications which expect overlays: the application must define a way for overlay developers to identify their content elements. The id attribute of XUL elements is particularly troublesome. After all, anyone could have this:
<vbox id="contentBox"/>
So if you have that in your overlay, and I have a similar element in my overlay:
<textbox id="contentBox"/>
Immediately one of us has a problem. The application should have defined for us a way to avoid ID collisions like this. At the very least, it breaks the DOM's getElementById method.
A few days ago, I blogged about a JavaScript scope registry. I thought to myself, "if we have a unique scope id for the scripts, I can reuse that as an attribute in the overlay."
So instead of relying on a single ID attribute to identify an element, I can rely on a two-part key: a scopeid attribute on an ancestor element, and a localid attribute on the target node.
Thus, I present a simple function for getting a node by this combination key:
document.getElementByAttrKey = function byAttrKey(aScopeId, aLocalId) {
var scopeElements = document.getElementsByAttribute("scopeid", aScopeId);
if (!scopeElements)
return null;
for (var ptr = 0; ptr < scopeElements.length; ptr++) {
var list = scopeElements[ptr].getElementsByAttribute("localid", aLocalId);
if (!list)
continue;
return list[0];
}
return null;
}
It is probably more efficient to cache these nodes in a registry, though.
UPDATE: I love it when someone comes up with a cleaner solution than me. Thank you, Mr. Karel. Still, the premise (that id alone is not enough) holds.
Posted by WeirdAl at May 14, 2005 11:41 PMWhy not to use name spaces? An ID reference would then look like id=myNameSpace.actualID
(From Alex: That's just more characters for people to type and more complicated.)
Posted by: funTomas at May 15, 2005 4:14 AMUm... XPath!
var xpath = '//[@scopeid="' + aScopeId + '"]/[@localid="'+ aLocalId +'"]';
var nodes = document.evaluate(xpath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
// return (nodes.snapshotLength > 0) ? nodes.snapshotItem(0) : null;
(From Alex: I feel dumb. That's a better solution, though XPath suggests //(scopeidtest)//(localidtest). :) )
Posted by: Ben Karel at May 15, 2005 9:39 AM