Implementing a DOM in JavaScript?

I know, that sounds crazy, but hear me out…

In recent weeks, I’ve begun to suspect the singularity is near, really, in JavaScript land. After all, we now have just-in-time compilation (in at least two flavors for Mozilla code alone), the Bespin SkyWriter editor project, the new JS Reflect API, Narcissus and Zaphod… it’s a pretty exciting time.

Also at work, I’ve been seriously exposed to jQuery for the very first time. I’d heard of it and similar libraries (Dojo, Yahoo UI widgets come to mind), and what they do is provide abstractions of the underlying DOM for common operations.

Mix that concept (abstracting the DOM) with Narcissus’s concept (a JavaScript engine implemented in JavaScript), and I start to wonder. What if we implemented a complete DOM in JavaScript, on top of the existing DOM – and then used that JS-layer DOM to implement our own features?

A few years ago, when XBL 2 was first announced, someone suggested they could implement the specification in JavaScript. Someone wiser (I think it was bz, but I don’t remember) replied that this implementation really didn’t do it, since the nodes weren’t really hidden. But if we implemented a full DOM layer in JS, and modified that…

For instance, take Node.firstChild:

JSNode.prototype = {
// ...
get firstChild() {
if (this.DOMLayer.hasSpecialFirstChild(this))
return this.DOMLayer.getSpecialFirstChild(this);
var returnNode = this.innerDOM.firstChild;
while (returnNode && this.DOMLayer.isHidden(returnNode)) {
if (this.DOMLayer.hasSpecialNextSibling(returnNode))
returnNode = this.DOMLayer.getSpecialNextSibling(returnNode);
else
returnNode = returnNode.nextSibling;
}
return this.DOMLayer.wrapNode(returnNode);
},
// ...
}

As long as everything was wrapped in a complete and well-tested DOM abstraction layer like this – and only objects from the abstraction layer were returned to the user – you’d have a baseline for creating (or at least emulating) a whole new way of viewing the DOM. XBL 2 could be implemented by manipulating this JS-based DOM.

You could also experiment with other possibilities. I’m running into a problem where I would really like to hide some nodes from the DOM Core interfaces (particularly previousSibling and nextSibling), but expose them through other means. My first thought was to use node filtering to skip past them (you’ll hear more about that in another blog post), but I wonder if I’m just wall-papering over the real problem or actually solving my immediate problem.

I could even use this idea to get past three of my fundamental problems:

  • XTF, while beautiful for my purposes, isn’t well-supported, and XBL 2 is supposed to make it go away. I don’t know when, but I find myself using more and more of XTF’s features – particularly its notifications – in recent months. If XBL 2 really replaces XTF, it’s going to be more and more difficult to update my code. A JS-based DOM means I can just walk away from XTF entirely.
  • Recently, I found myself hacking the core DOM to support observer notifications from Node.cloneNode(), so that I could manipulate the DOM before and after a clone operation. That’s not a very nice thing to do, but I have my reasons. I can modify a JS-based DOM to avoid that step entirely.
  • At some point, I’d like to implement the Entity and EntityReference parts of the DOM Level 1 Core specification. When it comes to editing XML, DTD’s and entities matter (see localization), but they’re a pain to work with.

Of course, there are some logistical problems with building a JS-based DOM. For one thing, there are a lot of DOM specifications to implement or wrap in this way. This abstraction layer would have to pass a pretty large set of tests too.

If you did all that, though, and could run it a couple layers deep (one JS-DOM layer on top of another JS-DOM layer on top of the native DOM layer) accurately… that would be a pretty good starting point for lots of custom DOM manipulations.

A search on Google didn’t turn up anything like what I detail above. Is there anyone crazy enough to write a narcissistic DOM? Given that I might need this anyway at some point in time, should I seriously consider doing this for my own project? Or is this just a really bad idea?

7 thoughts on “Implementing a DOM in JavaScript?”

  1. Personally I think it’s a great idea… but then I work with remote XUL and am having to plan a migration to HTML. We’ve looked at the JS XBL2 implementation, but it’s been pretty much abandoned due to the shadow tree issue, so if a JS DOM made that viable again it would be a huge boon.
    It would also be useful for mass DOM updates that can then be applied to the live DOM as a single operation.

  2. A few people have started doing this (including me). I’m not aware of any released products yet. A few comments:
    – I assume you mean DOM virtualization, not abstraction
    – JS-DOM needs to implement node-lists. I don’t think it is possible to implement a strict node-list in today’s JS. However, near-enough might be good-enough.
    – JS-DOM also needs to intercept every single event.
    – if JS-DOM is to work on any version of IE prior to IE9 then DOM properties won’t be implementable, except with exposed getter and setter functions.
    – regarding XBL2, the big problem is fixing CSS, not fixing DOM accessors.
    – the XBL2 dialog you recalled is probably https://weblogs.mozillazine.org/roc/archives/2008/03/not_a_crossbrow.html
    cheers,
    Sean

  3. I scratched out a note to myself somewhat related to this line of thought a few months ago:

    Here’s a stupid thought.
    Say I have a node and I want to add a child to it. What do I pass to appendChild? A Node, right? Where do I get that node?
    “What do you mean?”
    Well, say I’m not moving existing nodes around, but I want to append something wholly synthesized for some purpose.
    “If we’re talking about elements. You’d want to do document.createElement and then manipulate the result to get it into the state you desire before appending it..”
    Sure, for the sake of this example, I’ll allow that we talk about elements here, but my overarching point is applicable to all kinds of nodes—all kinds of DOM interfaces in general. Now, document.createElement is fine, but what if I wanted to append something, like I said, wholly synthesized? What if I wanted to append an element which had been implemented in JavaScript? An element is just (in theory) something that satisfies the DOM Element interface, soshouldn’t I be able to say el.appendChild(el.ownerDocument.importNode(synthesizedNode))?

  4. You’re talking about jQuery … if you code something like this, please make it more like MooTools or Prototype than jQuery because the latter (though being easy and useful on the surface) is a pain in the a** when you dig deeper and want to do something more extraordinary (and I’m not talking about effects).
    See jqueryvsmootools dot com for some further details.

Comments are closed.