ripper.rhetoric

Thursday, March 30, 2006

activateActiveX

Recently, Microsoft lost a patent battle with Eolas that will affect the ActiveX functionality of Internet Explorer. Now, while I know a lot of people aren't too fond of ActiveX controls, they do have their uses and a lot of websites will be affected by this change. In about 60 days your users will start having to click any HTML elements using object, applet, or embed.

Microsoft has posted solutions and work-arounds to the problem, but as an experiment in JavaScript and the DOM, I wanted to create a script that would dynamically solve the problem on any page it's attached to.

After reading the MSDN article, I started experimenting with removing the elements from the DOM, and trying to reinsert them. In lieu of having to hand code every possible object property, I went in the direction of enumerating the objects to read the properties. That didn't work so well, as the objects have child objects that go on into infinity. My next attempt was just reusing the same object, and that failed as well...it seems Internet Explorer 7 stores info in the object itself that says it hasn't been activated yet. But, after some playing around I found the solution: remove the object via the DOM and reset the innerHTML value of the parent element.

Now, while it seems that this is just a quick fix for the lazy, it does have some real applications that couldn't be done otherwise, like fixing ColdFusion generated Flash Forms.

There are two flavors available for download:

Header version that traps the window.onload event and can be put in <head> section of your HTML document for clean, well formed code.

Footer version that won't interfere with existing window.onload events, but must be placed at the end of the HTML document.

Installation instructions are in the file. Enjoy!

Update 4/17/06:
After the final Microsoft updates, this page has been getting a lot more traffic, and some people have been emailing me about issues. It seems that this trick doesn't want to work for Shockwave elements, and people are having problems using <param> values for Flash. I will look into tweaking the script to handle this.

Update 4/4/06:
Some people have had a problem with using this script on their local machine. Internet Explorer will prompt you to let this script run if you load it locally for security reasons. However, the Internet security zone will not ask this question and will run the code without any security notifications. An example of the code in action can be found here.

Also, a comment was left that said IE7 can't tell that the objects have been loaded. This does not happen in IE6, and if anyone has an idea on how to fix this, please let me know.

5 Comments:

  • This comment has been removed by a blog administrator.

    By Blogger Wes, at 12:10 PM  

  • Brilliant :-) Up until an hour ago I was thinking the exact same thing! I tried reusing the object first, which as you point out didn't work.

    I then had a go at creating a new object and setting all attributes the same as the existing object before doing the same with the child params. This seemed to cause a problem with the Flash movie not loading, which is where I stopped to get some other work done.

    Just searched digg to see if anyone else had come up with this yet in case I was wasting my time and I was pleased to see I was :-)

    I'd got this so far:

    var objects = document.getElementsByTagName('object');
    for (var i = 0; i < objects.length; i++) {
    var oldObject = objects[i];

    var newObject = document.createElement('object');
    // should loop and get the attributes instead
    newObject.width = oldObject.width;
    newObject.height = oldObject.height;
    newObject.type = oldObject.type;
    newObject.data = oldObject.data;

    var params = oldObject.getElementsByTagName('param');
    for (var j = 0; j < params.length; j++) {
    var newParam = document.createElement('param');
    newParam.name = params[j].name;
    newParam.value = params[j].value;
    newObject.appendChild(newParam);
    }

    var parent = oldObject.parentNode;
    parent.replaceChild(newObject, oldObject);
    }

    By Blogger Wes, at 12:14 PM  

  • It is a brilliant solution, but I don't believe it is 100% done yet. On IE7 it causes the browser to think the page is still loading. At the bottom of my page it says (10 items remaining) forever. I have 10 Flash objects on the page. Also, I don't think it will work for shockwave objects.

    By Blogger Rich, at 7:07 AM  

  • I developed a similar solution, but the nested loop would have just one line:
    element.outerHTML = element.outerHTML;

    Do you see any adverse consequences this alternate approach?

    By Blogger Av, at 10:06 AM  

  • Hi

    I like the idea, but I'm not sure the appproach works.

    I think rich's issue is explained by the following note. I think he's trying the to use the footer technique.

    When the page is loading the flash movies are requested from the server. The code then removes the references to those requests and re-adds them which creates new reqests for each flash movie. If you use a tool like fiddler (www.fiddlertool.com) you can see 2 requests for each flash movie.

    Consequently the browser will never finish downloading the page. Another side effect of this is the onload event will never fire.

    If you can't reproduce this issue, put more than one flash movie on your page. I see this problem on IE6, WinXP sp2.

    I'm not sure how to fix this. Is it possible to determine if the first request for the flash movie has completed before replacing it with the new version?

    This issue appears to be resolved using the onload technique. However, if you already have an onload element in the body tag, it will overwrite the activate ActiveX function and it doesn't run.

    Also, for larger flash movies, a user will see both movies (unactivated and ativated).

    By Blogger craig, at 12:09 PM  

Post a Comment

<< Home