Perfection kills

Exploring Javascript by example

DOMLint – resolving name conflicts

March 9th, 2009 by kangax (Permalink)

DOMLint test suite

One stupid aspect of DOM is the way it allows to access certain elements as properties of their containing “parent” element. Form controls, for example, can be accessed by their “name” through property access of <form> element containing them:

<form>
  <input type="text" name="foo">
</form>
...
document.forms[0].foo; // "[object HTMLInputElement]"

At first, this might seem like a great convenience – surely, it’s easier to write formElement.foo rather than a more verbose formElement.elements.foo. The joy of convenience, unfortunately, starts to fade out once you realize how badly DOM handles conflicts between these “magic” properties and actual properties of a parent element defined as part of its standard DOM interface. Form elements, for example, implement HTMLFormElement interface and that interface consists of 8 properties – elements, length, name, acceptCharset, action, enctype, method, target and 2 methods – submit and reset. The form doesn’t just have these properties. DOM says that HTMLFormElement should inherit from HTMLElement, which in its turn inherits from Element which inherits from Node and so on…

What this means is that a very simple form element happens to have a bunch of very useful methods inherited through one of its numerous interfaces.

What happens if we try to “magically” access an element whose name matches one of those “interface” properties? Do we get an element or a property/method? The horrible truth is that we usually get an element. Magical properties turn out to be too magical and shamelessly shadow all of those useful methods we might need to use:

<form>
  <input type="text" name="submit" value="Submit!">
  <input type="text" name="style">
</form>
...
<script type="text/javascript">
  document.forms[0].submit; // "[object HTMLInputElement]"
  document.forms[0].style; // "[object HTMLInputElement]"
</script>

Just like that, having 2 simple elements with somewhat unfortunate names, we end up not being able to use a very crucial `submit` method, and a not less useful `style` property.

Even creepier examples demonstrate that names on form elements themselves can cause the same mess:

<form name="getElementById">
  ...
</form>
<form name="body">
  ...
</form>
...
<script type="text/javascript">
  document.getElementById; // "[object HTMLFormElement]"
  document.body; // "[object HTMLFormElement]"
</script>

and -

<form name="window" onclick="console.log(window, setInterval)">
  <input name="setInterval">
</form>
// when clicked, logs [object HTMLFormElement], [object HTMLInputElement]

The latter example actually shows another annoyance – scopes of intrinsic event handlers being augmented with element object (as well as a document that an element is contained within).

When working with legacy documents, such unsafe names can lead to quite nightmarish debugging sessions. This is why I created a simple test suite to catch the offenders. It’s called DOMLint and is powered by a wonderful YQL. It is also hosted on github.

DOMLint is a work in progress. It doesn’t yet catch as many of the unsafe names as it could. Finding all of the names is impossible, since many browsers implement proprietary members on global object, document or elements. It nevertheless covers many of the most common ones. Currently, the project page performs 6 tests including the one for Prototype.js conflicts. Each test is thoroughly explained and is accompanied by an example.

I’d like to thank Garrett Smith, whose Unsafe names article made me aware of these issues and has eventually inspired to create a DOMLint. Garrett goes into much more details on the subject and covers even more failing cases. I highly recommend reading it.

I haven’t had time to find out whether YQL allows to send documents as text, so for now the tests are performed against a URL. If you have any suggestions or comments, I will be more than happy to hear them out.

Categories: DOMLint, annoyances 7 Comments »

Comments (7)

  1. Gravatar

    James said:

    I first heard about this on Resig’s blog; he was mainly focusing on the ‘length’ property and how any element with an id of ‘length’ would screw everything up in IE – http://ejohn.org/blog/deadly-expandos/

    I think it’s quite a serious issue to be honest, and I’m surprised these DOM-0 ‘features’ haven’t been phased out yet! I understand why they existed originally but now they’re just unnecessary abstractions!

    The real problem occurs when someone who knows nothing about the DOM uses a framework. it’s a problem because these people will blindly name their forms incorrectly and then it’s on the framework’s shoulders to fix it. I don’t feel that frameworks should have to cater to ignorance.

    Your DOMLint service is pretty cool and a very inventive implementation of YQL – I’ve always wanted to try that out; it looks awesome. Do you have any plans for making a bookmarklet?

  2. Gravatar

    Simon Kenyon Shepard said:

    Hey,

    great work! – I too saw this on Resig’s blog and left a comment saying it would be great to create a lint style product to check for this, now I don’t have to!

  3. Gravatar

    kangax (article author) said:

    @James

    Yes, I’m surprised myself that browsers still support this nonsense. I suppose the reasonings being that of “not breaking the web”, as there still seem to be scripts out there relying on such “features”. I’m not sure about bookmarklet, but there are things I want to improve in domlint itself (being able to paste document, which might have been on an intranet, is main priority at the moment).

    @Simon

    Thanks! :)

  4. Gravatar

    wow said:

    very good…..

  5. Gravatar

    wow said:

    very good…

Trackbacks

  1. Ajaxian » DOMLint: Checking for Form Conflicts said:

    [...] few days ago, Prototype developer Juriy Zaytsev announced a new utility, DOMLint. It aims to solve an obscure but important problem with forms and JavaScript: Form [...]

  2. DOMLint: Checking for Form Conflicts | Guilda Blog said:

    [...] few days ago, Prototype developer Juriy Zaytsev announced a new utility, DOMLint. It aims to solve an obscure but important problem with forms and JavaScript: Form [...]

Leave a Comment

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Please, don't forget to escape your input (<, > and &). Wrap code sections with <pre>