Thursday, July 22, 2004

Table rows...revealed!

By setting the CSS rule display:none on a TR element, you can collapse and hide whole rows of table data from the user. This is a popular technique for managing the visual display of tabular data in a web application.

However, there's a small challenge that arises when we attempt to make the TR visible. The intuitive thing to try is to set the CSS display property to block. IE is perfectly happy with this, but Firefox 0.8 mangles the final rendering, as this screenshot shows:

table-row-display.png

The proper CSS rule should be display:table-row. Firefox like this a lot better and expands the TR without the mangling. But IE for Windows will throw an error, because — unlike its MacIE cousin — it doesn't support table-row.

What to do? Aside from waiting for IE to support table-row or for Firefox to support block in place of it, the simple solution is to set the CSS display property to an empty string. Both Firefox and IE should fall back on their respective default values.

Try this example:

<script type="text/javascript">
function applyDisplay(value)
{
 document.getElementById("foo").style.display = value;
}
</script>

<table border="1">
<tr><td>R1 C1</td><td>R1 C2</td><td>R1 C3</td></tr>
<tr><td>R2 C1</td><td>R2 C2</td><td>R2 C3</td></tr>
<tr id="foo"><td>R3 C1</td><td>R3 C2</td><td>R3 C3</td></tr>
</table>

<p>
<a href="#" 
   onclick="applyDisplay('none'); return false;">
   Apply "display:none" to Row 3
</a><br>
<a href="#" 
   onclick="applyDisplay('block'); return false;">
   Apply "display:block" to Row 3
</a> (error in IE)<br>
<a href="#" 
   onclick="applyDisplay('table-row'); return false;">
   Apply "display:table-row" to Row 3
</a> (mangled display in Firefox)<br>
<a href="#" 
   onclick="applyDisplay(''); return false;">
   Apply "display:" to Row 3
</a> (should work in both)
</p>

Wednesday, July 21, 2004

What's in a NAME?

The little-used getElementsByName() method is part of the DOM Level 1 specification and is supported by both Internet Explorer and Mozilla/Firefox. getElementsByName() is part of the HTML application of the DOM, meaning it is specific to HTML documents, and explains why you won't find it in the DOM Core spec, which applies to any XML-like document.

Given a string as an argument, getElementsByName() retrieves all elements that have a NAME attribute that matches that string. Or does it?

<div name="foo">DIV one</div>
<div name="foo">DIV two</div>
<div name="foo">DIV three</div>

<script type="text/javascript">
var divs = document.getElementsByName("foo");
alert(divs.length);
</script>

Moz/Firefox will report a length of 3. MSIE will report a length of zero. Huh?

According to the HTML 4.01 spec, the only elements that support NAME attributes are BUTTON, TEXTAREA, APPLET, SELECT, FORM, FRAME, IFRAME, IMG, A, INPUT, OBJECT, MAP, PARAM and META. So to place a NAME inside a DIV is actually invalid HTML.

Moz/Firefox doesn't have a problem with this and will happily return all three DIV elements. But MSIE treats it the invalid NAME attribute as an expando attribute and excludes those elements. From the MSDN documentation:

"Elements that support both the NAME and the ID attribute are included in the collection returned by the getElementsByName method, but not elements with a NAME expando."

It seems that MSIE's implementation of getElementsByName() is actually more compliant with the W3C standard than Moz/Firefox's. Just not nearly as useful.

Tuesday, July 20, 2004

Form values and innerHTML

Alan Taylor has discovered another intriguing JS quirk: changing form values in Internet Explorer actually changes the underlying HTML structure, so that the value returned by innerHTML is altered. See Alan's example here.

Friday, July 16, 2004

Script-killer comments

This one seems like a no-brainer, but it had several of our best JS experts stumped for a good while, until we saw what was right in front of us all along.

A script for preloading images was failing. The source was similar to this (imagine 20 or more lines of unbroken script):

<script type="text/javascript">
<!-- preload_images ("header1.gif", "header2.gif", "logo.gif");
//-->
</script>

Notice how the first line of script is preceded by an HTML comment delimiter. This prevented the preload_images function from running, as the JS interpreter just skipped over the entire line. For the want of a linebreak, the script was hosed.

This seems to be common when JS is generated from some backend process. The above JavaScript was generated from a server-side application written in C++.

Thursday, July 15, 2004

Window args and errors

What's wrong with this picture?

window.open("example.html","Example Window",
"scrollbars=no");

Moz/Firefox will pop open a new window, but IE6 will throw an "Invalid Argument" error. Why?

The second argument to window.open is the name of the window. In IE6, this cannot contain any spaces or special characters. Some people mistakenly think this argument is for the title of the window. So they put in something human-readable (like "Example Window"), thus the error.

Wednesday, July 14, 2004

Array length headaches

A co-worker of mine stumbled across this little gem:

var foo = ['a', 'b', 'c', 'd',];
document.write(foo.length);

Moz/Firefox will print 4. IE6 will print 5. Why?

Look again at the array. See the extra comma on the right? IE6 interprets this as an additional element with an undefined value. Moz/Firefox ignores it.