October 4th, 2005

IE assumes .CSV is HTML, Firefox and Opera get it right. [part 2]

[…continued]

So, I decided to try to write a ‘bookmarklet’ (or ‘favelet’ as they’re sometimes called in the IE world), because I’ve been finding a lot of useful ones lately, and I often find myself throwing javascript into my address bar by hand to modify a particular page’s behavior. Before writing one myself, I searched for a while to see if it’s been done already. I wasn’t able to find any javascript code to transform a page of .CSV data into a more readable form (namely, an HTML table). I did find a CSV Converter page, which lets you paste CSV data into a textarea (or upload a file) and submit it to a CGI script, which returns the data as either HTML tables or WikiMedia format. I first tried writing a bookmarklet to submit the current page’s body to that CGI script.

But that didn’t work so well. Part of the problem, from what I could see, is that when IE rendered the page as HTML, the carriage-return/line-feed characters were replaced by a space. This presented a challenge for programatically parsing the CSV text, because now I had to know how many columns existed in the data, so I could figure out where to break the lines, so the table would have more than one row. (My earliest attempts produced a table with only one row, with LOTS of columns)

So, I ended up cheating a little bit, and requiring that the data in the first column on the second row will always be ‘IE’. Other than that, the bookmarklet I created can handle more columnns in the future, automatically.

Right click this link and add to Favorites/Bookmarks

If you’d just like to look at the code, click here to see it in a more readable form.

Well, wouldn’t you know it… this bookmarklet works in IE 5.01, IE 5.5, Firefox 1.07, and Opera 8.5, but NOT IN IE 6.0. The exact same browser whose shortcomings I was trying to work around. (The earlier IE versions also made the CSV == HTML assumption, but at least my bookmarklet worked in those versions). IE 6.0 did not generate any javascript errors when running the script, nor did it pop up its little security warning bar, or any other visible behavior. It just sat there.

I give up. Stupid IE.

To see the behavior (or lack thereof) of the bookmarklets above:

  1. right click it and add it to your favorites/bookmarks
  2. go to one of the CSV pages (all 3 files are the same–they just have different extensions):
  3. select the bookmarklet from your favorites/bookmarks list to run the script

Doing this with different browsers will unfortunately yield different behavior. If anyone can suggest how to make it work in IE 6.0, or how to fix it so it doesn’t require ‘IE’ to be the first value on the second line of the CSV file, I’d love to hear about it!

October 3rd, 2005

IE assumes .CSV is HTML, Firefox and Opera get it right.

Sooo… I posted that .csv (comma-separated values) file containing some benchmarks as part of my previous post on the performance differences between browsers when populating multiple select boxes in 2 different ways. What I didn’t notice until later, though, is that that file looks like crap if you click the link to it in Internet Explorer. IE seems to make an assumption like “Hmm, it doesn’t have extension ‘.txt’, so it must be HTML!” and it renders it as such. Of course, this .csv file doesn’t contain any HTML tags, so it doesn’t look pretty when IE makes that assumption:
MultiSelectPerformance.csv

For comparison, I made 2 copies of the CSV file:
MultiSelectPerformance.csv.txt
MultiSelectPerformance.csv.html

When I tried clicking the original .csv file link in Firefox and in Opera 8.5, they both behaved as I believe they should. They asked me if I wanted to open the .csv file with the application that is registered in Windows to handle files with that extension, Microsoft Excel, or if I wanted to save it to disk, or cancel.

Screenshots of those dialogs:

Firefox CSV file open dialog Opera CSV file open dialog

It strikes me as odd that IE, with its litigiously tight integration with Windows, didn’t bother to check the Windows File Types list before jumping to the strange conclusion that .CSV is a typo for .HTML. It’s possible that I could change my web server config files so it would send an appropriate ‘Content-type:’ header when .CSV files are served. But screw that, this is a stupid behavior in one browser, and I may want to serve a .CSV file on a web server someday where I can’t touch the config files. I was determined to do something to handle it on the client side.

[to be continued…]

September 29th, 2005

Comparison of Multiple Select Box Population Performance

I was recently working on developing a web application for a team project at school, when I ran into a little problem. We had a list of 1881 items to put in a select box. That, in itself, was a no-brainer. The problem was, we wanted to have 10 select boxes on this page, each with all 1881 items in it.

So, since I was using JSP, I pulled the entire list of OPTION tags out and stuck it in a separate file, then used the include directive, like:

< %@ include file=”optionList.jsp” % >

inside each of the 10 sets of SELECT tags, so the list was only stored in one place. However, this optionList.jsp file was 59KB, and this page needed to load reasonably fast, despite being served off my home server with a cable modem, and viewed at school with a flaky, unreliable wireless connection. Therefore, a page with over 590KB worth of text/html was just not going to work.

Well, I’ve dealt with manipulating select boxes using JavaScript before, so I decided to try putting all the options into an array of strings, and looping through each select box, and each element of the option array, to add all the options. Well, this worked fine in Firefox, but in IE, it took a ridiculous amount of time (roughly 2 minutes). With that kind of performance, we might as well just load the 590+ KB original page!

So, I did some research into javascript optimization, and explored the W3C DOM spec extensively. I created about 10 different methods of populating the select boxes, and ran each of them with timing code around them, in IE and Firefox. Eventually, I found a solution that performed reasonably well in IE and Firefox, and used it for the team project.

The key lines of code are:

var tmp = document.getElementById(’selectBox_0′).cloneNode(true);
// …
var selectN = document.getElementById(’selectBox_’ + pickNum);
// …
selectN.parentNode.replaceChild(tmp, selectN);

Basically, I created the first select box one option at a time, then cloned that select box object (with the ‘true’ parameter, to clone all child nodes as well) and replaced all the other select boxes with the clones. Then, I set some properties on the clones to make them unique (IDs, default blank options, etc). Dramatically faster than the other.

I’ve put together a benchmark page to test/demonstrate the original method of populating the select boxes (adding one option at a time, to one select box at a time), versus the method I found that worked so well. Then I ran the benchmark on several browsers, on several computers, and had some friends and co-workers try it, too. You can find the benchmark page here:

http://www.oatmealcookies.org/blogdl/
performance/MultiSelectPerformance.html

The benchmark results, as I’ve recorded them so far, can be found in a comma-delimited text file at:

http://www.oatmealcookies.org/blogdl/
performance/MultiSelectPerformance.csv

I recently found out that Opera 8.02 works about as fast as Firefox, even faster in some cases. I was impressed that the code that I’d tested thoroughly in IE and Firefox (but not Opera) actually RAN without errors, but the fact that it ran so fast was pretty cool.

Please feel free to run the benchmark and send me your results! The way that these measurements have been recorded is:

Click ‘Run All’.. when tests are complete (ranges from 12 seconds to 5 minutes, depending on browser and platform), click ‘Save Data’, which populates a textarea at the bottom of the page, and selects it, so you can then copy it to your clipboard and post it in a comment on this blog entry. Please include all fields that are in that CSV file, including browser versions, OS, processor speed, etc.