Fćrslur föstudaginn 24. nóvember 2006

At 02:12: The Elegant, Unobtrusive Javascript Workaround for "Click to activate and use this control" 

Recent versions of Microsoft's Internet Explorer (6+), trace an ugly gray border around all multi-media objects embedded in web pages (Flash, Java applets, Media player widgets, etc.) and require an extra "activation" click before they can be used. This annoying feature was brought on by a stupid patent lawsuit, which Microsoft lost. (First time in years that I side with Microsoft on something.)

Several workarounds exist floating around the Interweb, including one distributed by Adobe (ick!), but they're all really, really, really ugly:

  • Big, fat, and inefficient Javascript code.
  • Require Javascript running to see the multi-media object at all.
  • Require a major overhaul in how you embed multi-media objects in your pages.

This got me interested in writing my own piece of code that would be a) small and fast, and b) get the job done in as elegantly, unobtrusively as possible.

Here's what I came up with at work...

Step 0:

Embed your multi-media objects in your HTML as normal (using <object>, <embed> or <applet>). Leave them as they are. No changes required in your HTML.

Step 1:

Update July 3nd 2007: Posted what is hopefully the last update for a while now, added a workaround for the "IE-never-stops-downloading" bug. The compressed size is up by almost 200 bytes though.
Update June 6th 2007: Finally updated the code to address <embed> and <applet> tags, and to run also in Opera 9, after an helpful comment by David Muńoz. The minified version of the script is still only 395 bytes!
Update Dec. 13th: Changed the script below to make it even smaller and faster, and to solve an issue reported by Martin.

Copy and paste this Javascript code into a file and let's save it as "eolasfix.js".

// Documentation & updates available at:
// http://codecentre.eplica.is/js/eolasfix/test.htm

(function( Eolas_Fixed,
            win, doc,
            getElementsByTagName,
            outerHTML,
            parentNode,
            tags,
            elmsToRemoveOnload,
            x,
            is_ie,
            y,z,elm,childNode,HTML,dummy,eolasfix)
{
  // run only once!
  if (win[Eolas_Fixed]) return;
  win[Eolas_Fixed] = 1;

  eolasfix = function ()
  {
    // for each tag name specified in Array t
    while (tags[++x])
    {
      // find all elements of that type in the document
      // loop through the elements
      y = 0;
      while (elm = doc[getElementsByTagName](tags[x])[y++])
      {
        if (is_ie)
        {
          HTML = '>';
          z = 0;
          // <param> elements don't show up in innerHTML IE
          // so we need to collect their outerHTML.
          while (childNode = elm.childNodes[z++])
              HTML += childNode[outerHTML];

          // create a 'dummy' element 
          dummy = doc.createElement('i');
          // inject it next to `elm`,
          elm[parentNode].insertBefore(dummy, elm);
          // and turn it into an `elm` clone
          dummy[outerHTML] = elm[outerHTML].replace(/>/, HTML);
          // increment y to skip over it
          y++;

          // then hide the original elm
          elm.style.display = 'none';
          // and save it in 'The List of Elements to Remove Later'.
          elmsToRemoveOnload[elmsToRemoveOnload.length] = elm;
        }
        else
        {
          elm[outerHTML] = elm[outerHTML];
        }
      }
    }
  };

  // For IE run the fix straight away (because the defer="defer"
  // attribute has delayed execution until the DOM has loaded).
  // Then assign a window.onload event to purge the old elements.
  is_ie && !eolasfix() && win.attachEvent('onload', function(){
    x=0;
    while(elm = elmsToRemoveOnload[x++])
        elm[parentNode].removeChild(elm);
  });
  // For Opera set an `DOMContentLoaded` event to run the fix.
  win.opera && doc.addEventListener('DOMContentLoaded', eolasfix, 0);

})( '__Eolas_Fixed',
    window, document,
    'getElementsByTagName',
    'outerHTML',
    'parentNode',
    ['object','embed','applet'],
    [],
    -1 /*@cc_on,1 @*/
  );
The first and the last line wrap the function in a Microsoft-only [conditional compilation][1] directive - to make sure only Internet Explorer 6+ runs it.

The code is wrapped in a self-executing anonymous function to avoid polluting the global name space - with the notable exception of one global variable __Eolas_Fixed which is used to make sure the script runs only once (in case it gets linked to more than once within a single web-page).

The rest is hopefully fairly self-explanatory, albeit a bit "kludgy" looking, in part because of IE's quirkiness when it comes to working with <param> elements, and furthermore because I'm optimizing the code for "minification".

Step 2:

Paste the following code-block somewhere (anywhere!) in the HTML of your page:

<script defer="defer" src="[script-folder-path]/eolasfix.js" type="text/javascript"></script>

Note: The code is wrapped inside Microsoft's proprietary conditional comment block, so all other browsers will gladly skip over it. Also: The defer attribute tells Internet Explorer to run the script as soon as the page's HTML has finished loading, to ensure we catch all embedded objects on the page. Opera, on the other hand, gets instuctions to delay execution until onDOMContentLoaded.

Step 3:

There's no Step 3. That's all.

See the online demo if you don't believe me. :-)

Licence

My employer says: Feel free to use this code in any way you like as long as the version version you distrubute includes a comment with an URL pointer to the demo page.

Reader comments (58) | Permalink


 

Flakk um vefsvćđiđ



 

Fćrslur í nóvember 2006

nóvember 2006
SunMán ŢriMiđ FimFös Lau
      1. 2. 3. 4.
5. 6. 7. 8. 9. 10. 11.
12. 13. 14. 15. 16. 17. 18.
19. 20. 21. 22. 23. 24. 25.
26. 27. 28. 29. 30.    

Nýleg svör frá lesendum

  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Req.js - javascript lazy-loading and dependency managment made easy)
  • Rich (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Req.js - javascript lazy-loading and dependency managment made easy)
  • Dinesh (Req.js - javascript lazy-loading and dependency managment made easy)
  • Már (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • Ada (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • notandi (Taubleyjur í nútímanum - lítill leiđarvísir handa hrćddri ţjóđ)
  • Geir (Lausnin á efnahagsvandanum)
  • Jenný (Lausnin á efnahagsvandanum)
  • Óli Jens (Lausnin á efnahagsvandanum)
  • Már (Lausnin á efnahagsvandanum)
  • Kjartan S (Lausnin á efnahagsvandanum)

 

 

Yfirlit yfir ţetta skjal

(Atriđin í listanum vísa á ákveđna kafla ofar á síđunni.)