Rough Book

random musings of just another computer nerd

Tag: preview

innerHTML and createContextualFragment problems when Firefox renders XHTML

If any of you use Firefox, then you’ll have noticed that the “Preview Comment” feature doesn’t work anymore. It stopped working after I converted this site over to XHTML. Initially it worked (even though it validated as XHTML 1.1) because I was setting the mime-type to text/html. To make it completely compliant, I set the mime-type (for browsers that accept it) to application/xhtml+xml. This made certain things break in Firefox. Namely, innerHTML. HTMLElement.innerHTML isn’t a W3C standard anyway, so it would make sense that it wouldn’t work. However, it was not so much an error as it is a bug in Mozilla (or in Gecko).

I looked around for some alternatives and chanced upon the createContextualFragment function. It is supposed to work, but I guess those examples were for Firefox when it didn’t support the innerHTML property in HTML. I tried something like this:

var range = div_preview.ownerDocument.createRange();
            
range.selectNodeContents(div_preview);
range.deleteContents();

var fragment = range.createContextualFragment(comment); //<-- will crash here
div_preview.appendChild(fragment);

But that didn’t work either. I then found out that this is also a bug. I’ve got two pages demonstrating the bugs here and here.

I don’t have any other alternatives than to

  • Wait for Firefox 1.1
  • Parse the code I want to insert through an XML parser, and then create the objects through DOM Core methods

I figure I’ll try the option b for now, but I don’t know how the slow the parsing will be. I guess I won’t know until I try.

Preview Button and no more Iframes

I have added a “Preview Comments” button to the comment submission form. So now, you’re able to preview your comments before submitting them. The preview will show you your comments exactly as they will appear (after they have been submitted).

The other big thing is the removal of iframes. I thought iframes were really freaking awesome when I first found out about them. And they are. There are a bunch of cool things you can do with them. I always used iframes to update the contents of a page without refreshing the entire page itself. This was accomplished by submitting to a hidden iframe. The server-side script in the iframe would generate Javascript, which would then manipulate the DOM on the parent page. Pretty nifty. I learnt that when I was working at College of Business at ASU. It was something that the bunch of us (Chris, Kelly, Gravey, Cameron, and I) came up with in the Fall of 2001. We thought it was pretty novel.

I used iframes extensively in the last incarnation of my website. When that crashed and burned, I needed to make a new website. So I went ahead and used iframes on this one too. Somewhere along the way, I was possessed by the urge to make this website XHTML compatible. But alas, iframes didn’t pass the compatibility test. I then tried to find a replacement for iframes. The object tag seemed to work, except there was no way to make it reload. Then I tried XMLHttpRequest. This also seemed promising, but I had to make a bunch of changes to the Javascript. I didn’t feel like doing that. I also then realized that I wanted content to show up on search engines, and having an iframe wasn’t going to do that. So I then decided to re-design the backend completely. Instead of using an iframe, I would just dump content directly into the page. Of course, now it wouldn’t load the content seamlessly when you clicked on a date, but what the heck. I still had one iframe though – the one that populates the calendar. I figured there simply wasn’t any other way to do it, so I left it as it is.

It stayed that way until Marc left me a comment talking about the need for the functionality to preview comments. I was going to use the iframe, before I realized that the comments could have line-breaks, and all other kinds of nasty stuff that could mess up Javascript. I could have accessed the HTML from the iframe, and dumped it into the page, but the first thing that came to my mind was the XMLHttpRequest object. I used it to replace the iframe. I think it actually works a whole lot better, and is definitely more flexible. Even though the object is used for XML, you can get HTML through it as well through the responseText attribute. This way, you can simulate the action of submitting to a form, and then access the data generated by the server-side script. You can then do whatever you want with the data. This is definitely much more flexible than having to deal with Javascript from the action iframe.

In the course of all this, I wrote some (I think) pretty nifty code. I wrote two functions; getXMLHttpRequestObject creates an XMLHttpRequest object and returns it. I needed this function because IE and Firefox create the object differently. The other function, sendXMLHttpRequest sends the request to the server. The cool part is that I also send in a custom handler. When sendXMLHttpRequest finishes receiving the data from the server, it calls the custom handler with that data. Maybe not all that fancy, but I think it’s cool :). Here are what the functions look like:

getXMLHttpRequestObject:

function getXMLHttpRequestObject()
 {
          if(Firefox)
          {
             return new XMLHttpRequest();
          }

          else
          {
             return new ActiveXObject('Microsoft.XMLHTTP');
          }
 }

sendXMLHttpRequest:

function sendXMLHttpRequest(Request, uri, POSTdata, responseHandler)
 {
          Request.open("POST", uri, true);
          Request.setRequestHeader(
                                   'Content-Type',
                                   'application/x-www-form-urlencoded'
                                  );

          Request.onreadystatechange = function()
                                       {
                                                if(Request.readyState == 4)
                                                {
                                                   if(Request.status == 200)
                                                   {
                                                      responseHandler(Request.responseText);
                                                   }

                                                   else
                                                   {
                                                      alert("There was a problem retrieving data: " + Request.statusText);
                                                   }
                                                }
                                       }

          Request.send(POSTdata);
 }

A sample call is as follows:

function doSomething(param1, param2)
 {
          var Request = getXMLHttpRequestObject();
          var FormData = "param1=" + param1 + "&param2=" + param2;
          sendXMLHttpRequest(Request, "doit.php", FormData, myResponseTextHandler);
 }

 function myResponseTextHandler(text)
 {
          //do something with text
 }

Neat huh? Javascript is a whole lot more powerful than some people think. Ok, enough geek talk!

References:

All original content on these pages is fingerprinted and certified by Digiprove
%d bloggers like this: