On a recent project, I traveled to the depths of hell and came out alive. Here’s how it went down…
So the first problem we run into is that, by default, the MultiBox media type of youtube expects the link URL to point directly to the video and not to the video page on YouTube (one reason to ditch MultiBox). Note the difference in URLs below. The video identifier is the same in both (eCzEkiIucUk) but rather than passing it as a parameter to the ‘watch’ page, we can pass it as the slug to /v.
To deal with this, I wrote a quick script that executes
ondomready. It parses the v parameter value out of the query-string and rewrites the URL to point directly to the video. This way, when MultiBox opens and inspects the URL to load, the video itself is opened in the MultiBox pop-up rather than the entire YouTube page.
Roadblock #1 : MultiBox ‘types’
At this point, everything is working as expected until the client requests that we provide a customized fallback message for users without Flash. This is a perfectly reasonable request. Ideally the fallback content would be a transcript of the video and perhaps some still images from the video. Maybe even a link to the raw H.264 video. Of course, in this case we are requested to simply provide a ‘Please install Flash’ message. Unfortunately, MultiBox doesn’t have a way to provide custom fallback content for its youtube type. (Yet another reason to ditch MultiBox.)
Rather than using the youtube type and its out-of-the-box functionality, we’ll switch over to the element type. This type allows you to target an element in the dom and the targeted element (and children) is cloned into the MultiBox pop-up. For this to work, we’ll provide our own
object element, complete with cross-browser nesting of objects (see SWFObject static publishing) and our own custom no-flash fallback content. Each video thumbnail will now have the actual video markup next to it in the source, hidden via CSS. The thumbnail is marked up to link to the video page on YouTube (for JS-off users). On page load, the links are rewritten to point to the fragment identifier of the video object in the page (e.g.
href="#video1"). This way, when MultiBox is activated using the ‘element’ type, it will grab the
object element with
id="video1" and clone its contents into the pop-up.
Roadblock #2: MooTools ‘clone()’
object elements after they are inserted into the pop-ups, we notice that they no longer contain the
param children they’re supposed to. The original
object elements still contain their
param children, but the clones do not. Internally, MultiBox uses the MooTools
clone() method on the base Element class so I put together a quick test page to verify that MooTools’
clone() method works properly in IE6 on
object elements. It failed the test, and I filed a bug against MooTools.
The workaround for the MooTools
clone() bug is to use the old-school
innerHTML property ourselves rather than allowing MooTools to do proper DOM manipulation in the background. So I open up MultiBox and find the routine whereby it uses
clone() and add a quick hack. I check if the browser is IE6 and if so, use
innerHTML to copy the
object element (and all its children) into the pop-up.
Roadblock #3: IE6 ‘flashvars’
So now we have the object being correctly cloned into the pop-up when a user clicks the video thumbnail. An then I get another ticket. All the YouTube videos are playing, but the self-hosted video is not. Why is the video not playing? This particular video is played using a SWF player which takes the FLV file name to play via the
flashvars param. I notice that the FLV file isn’t being requested in IE6. But we just fixed the
param bug and the children are all there! Or are they really? After some more debugging and googling, I find that IE6 resets the value of the
flashvars param when its
innerHTML is modified.
You’re not surprised, are you?
After some more searching, I find a great blog post that describes the solution. Rather than passing the different variables to the flash player using the
flashvars param, we’ll just add them to the SWF query-string. So this:
Since we’re using SWFObject’s static publishing method, there are 2
object elements. One intended for IE, and another one, intended for everyone else. The proper
object (for Firefox, Chrome, et. al.) is nested within the IE
object and hidden via Conditional Comments. Since this whole
flashvars mess is only a problem for IE6, we only need to modify the outer
Roadblock #4: MultiBox’s flvplayer
Just when you thought we were out of the woods, we have one last issue. Now that we have the video objects with proper fallbacks, and the elements being cloned properly, and the config file information passed correctly, we still don’t have a functioning video in IE. Since we modified the outer IE object element, thanks to the previous issue, we’ve broken the video in all versions of IE. What’s the problem this time? It turns out that the flvplayer.swf that comes packaged with the phatfusion MultiBox doesn’t stream the video properly when the FLV file name is passed via query-string. Solution? Ditch phatfusion’s flvplayer and use another! (I recommend any of the JW players if your situation fits the non-commercial bill)
When the bugs align…
So at the end of this ordeal, I had three more reasons to avoid phatfusion’s MultiBox widget, I had filed yet another bug against MooTools, and I had conquered yet another bug in IE6. And it all piled up because of a tiny bug in a particular flvplayer; that was caused by the solution to a specific bug in IE6; which was only a problem because of a bug in a particular version of MooTools; which was only a problem because of a poorly designed API in MultiBox; which was encountered because the client wanted to display a download button for Flash; mostly for users who aren’t even able to install Flash if they wanted to. Don’t you just love web development?