June 04, 2009

swfLink: Simple, unobtrusive, Flash embedding

Update:Now returns the resulting <object> on success

I was in need of some simple Javascript to add SWF objects. Hoping for a simple, cross-browser, ie-proof, eolas-respectful and graceful-degradable solution is a difficult praise to attend, so I began, as always, to write my own.

The routine is so simple because it does nothing more than add a <object> tag so it can embed the flash movie. No plugin or software checks. I didn't need them.

The markup is easy as pie:

<a href="path/to/file.swf?parms" width="320" height="240">Alternate content</a>

A straightforward link to our swf, so, in non-js environments, the user can access it as well. The width and height must be specified too in order to create the <object> tag within the script.

Now the guts, the JS code to convert our links into fully-functional swf objects:

var links = document.getElementsByTagName('a');
for(var idx = links.length - 1; idx >= 0; --idx) {
  var item = links[idx];
  if(/\.swf[$?#]/.test(item.href)) {
    swfLink(item.href, item, {
      width: item.getAttribute('width'),
      height: item.getAttribute('height')
    })
  }
}

All it does is to get all links and filter the ones not corresponding to swf files. The /\.swf[$?#]/ regex is responsible for this to happen. You´re allowed to change that and make it more secure, but, for now, it fits my needs.

Next we move into the details of the swfLink script.

function  swfLink(url, elm, opts, parms) {
  // Default values
  opts = opts || {};
  parms = parms || {};
  !opts.type && (opts.type = 'application/x-shockwave-flash');
  !parms.allowscriptaccess && (parms.allowscriptaccess = 'always');
  !parms.wmode && (parms.wmode = 'transparent');
  // Checks for IE
  if(!+"\v1") {
    opts.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
    // Split URL onto movie and flashvars params
    url = url.split('?');
    parms.movie = url[0];
    url[1] && (parms.flashvars = url[1]);
  } else {
    opts.data = url;
  }
  var result = ['<object'];
  // Add options as object attributes
  for(var idx in opts) {
    result.push(' ', idx, '="', opts[idx], '"');
  }
  result.push('>');
  // Add params
  for(var idx in parms) {
    result.push('<param name="', idx, '" value="', parms[idx], '"/>');
  }
  result.push(elm.innerHTML, '</object>');
  var cont = document.createElement('div');
  cont.innerHTML = result.join('');
  // Replace source link with embedded object
  elm.parentNode.replaceChild(result = cont.firstChild, elm);
  return result
}

As you may note, I´ve used the 7 byte IE detection script in order to detect our natural enemy. The code is pretty straighforward, I think. It does only what it needs to be done.

I hope this helps somebody. At least I enjoy coding it.

How boring life would be without IE spicing up our coding time...