reptile7's JavaScript blog
Monday, January 25, 2010
JavaScript Flash Detection, Part 3
Blog Entry #169

We conclude today our discussion of HTML Goodies' "Test Visitors for the Flash Plug-In" tutorial; as promised, we'll revamp the tutorial's 'Flash sniffer' code in this post.

A new-and-improved Flash sniffer: less is more

Gateway/meta exit

In "Tip Twenty-One" of his "So You Want To Get Them All The Same, Huh?" article, Joe exhorts Web authors to [w]rite simply:
Yes, I know that animations, and JavaScript, and applets, and backgrounds are really cool. I like them just as much as you do. But go easy on the flash. Content should be your main concern. Text and static images make a very good page if the user is interested in what you've written.
Some may not like that reasoning because it means you cannot fill your pages with bells and whistles and the latest scripts that make images jump around. Just don't assume the user has the computer or browser to run the fancy formats. Always let the user see your simpler cross-browser page, then allow them...if they have the correct equipment [to] choose to see the latest thing.
To be sure, a Flash animation or video is ultimately an extra and not a necessity. The "Test Visitors for the Flash Plug-In" script's use of a gateway page and a meta refresh puts the FLASHPAGE.html and NON-FLASHPAGE.html destination pages on an equal footing - a bad call, IMO; in the spirit (if not quite per the letter) of the above tip, it would be better design to
(a) put the script in the NON-FLASHPAGE.html source, and then
(b) make NON-FLASHPAGE.html the default viewing page, allowing us to
(c) throw out the gateway page and meta refresh.

Alternatively, the meta refresh could be replaced by a server-side HTTP redirect, but I don't particularly like that idea.

No browser/platform sniffing, no custom properties, no with statement

Near the end of Blog Entry #12, I presented a short script that used a for loop, the navigator.plugins array, and the name property of the plugin object to step through and print out the plug-ins for a Classic Mac browser; that script is easily modified to flag a Flash plug-in:

for (var i = 0; i < navigator.plugins.length; i++) {
if (navigator.plugins[i].name == "Shockwave Flash")
window.location = "FLASHPAGE.html"; }

Use of a loop here is overkill, however. Given that individual plug-ins of a navigator.plugins array can be referenced associatively as well as ordinally (something I was unaware of prior to working through "Test Visitors for the Flash Plug-In"), it follows that

if (navigator.plugins && navigator.plugins["Shockwave Flash"])
window.location = "FLASHPAGE.html";

should be all we really need for a Flash redirection script - that's it - and in practice these two lines of code do the trick for the browsers on my computer in both the OS X and SheepShaver environments, with the following exceptions:
(1) Lynx 2.8.7, which doesn't support JavaScript in the first place;
(2) Netscape 3.04, a version of Netscape that predates Netscape's support for Flash (which began with Netscape 4.06);
(3) MSIE 4.5, which despite having a Flash plug-in does not support the navigator.plugins array; and
(4) MSIE 5.2.3, which on the PowerPC platform is compatible with Flash Player 8, which can be downloaded here* from; however, MSIE 5.2.3 does not recognize Flash Player 8 on my Intel Mac.
*At press time this link isn't working - perhaps you could try it later.
Hold it: That link now says, Flash Player is no longer available at OldApps - try this page instead.

But I'm a Mac user. What about MSIE for Windows, the 800-lb gorilla in the room? The absence of a plugin object on the MSDN Library's "DHTML Objects" page implies that MSIE for Windows does not support the Netscape plugin object API, even as I can confirm that the if (navigator.plugins && navigator.plugins["Shockwave Flash"]) test definitely works with MSIE 5.1.6 for the Mac in the SheepShaver environment. Moreover,'s "Plugin Object" page suggests that Microsoft implemented support for Netscape's plugin object in MSIE 4 for Windows. Hmmm, how to sort this out?

And then I remembered: all of the for-patron-use computers at my local library are PCs. I typed up in a systemstats.html file a small script containing the following blip of code based on my Blog Entry #12 script:

if (navigator.plugins && navigator.plugins.length != 0) {
for (i = 0; i < navigator.plugins.length; i++) {
document.write("(" + i + ") " + navigator.plugins[i].name + "<br>"); } }
else document.write("Sorry, no plugin information is available.");
/* The systemstats.html script also prints out the returns for navigator.appName, navigator.appVersion, navigator.userAgent, navigator.platform, and navigator.plugins itself. */

A browser that supports Netscape's plugin object will via the for loop print out a list of its plug-ins:

// My Opera plug-ins
(0) Shockwave for Director
(1) Shockwave Flash
(2) QuickTime Plug-in 7.6.4
(3) RealPlayer Plugin

In contrast, a browser for which the navigator.plugins and document.embeds arrays are equivalent - my operating assumption vis-à-vis MSIE for Windows - will via the else clause write out a Sorry, no plugin information is available message because the systemstats.html source doesn't contain any embed elements. In the name of completeness, I should note that a browser that supports the navigator.plugins array but doesn't have any plug-ins - an unlikely but possible scenario - will also write out the Sorry... message.
(I could have used a simpler script here, but I wanted to find out what plug-ins were on the library PCs in the event that the if condition returned true.)

I uploaded systemstats.html to my EarthLink server space and then walked over to the library. The library's PCs all run Windows XP, and the only browser installed on them is MSIE 8 - "The library's IT department won't let us install Firefox," a librarian told me. I logged onto a computer and launched MSIE. I first went to Adobe's Flash test page to check if the browser had a Flash plug-in: it did. I then surfed over to my systemstats.html page, at which I was greeted with Sorry, no plugin information is available. So I think we can safely conclude that MSIE for Windows does not support the Netscape plugin object API.

To my understanding, VBScript can be used to detect a Flash plug-in when using MSIE for Windows; however, I don't know anything about VBScript (nor do I have much of an incentive to learn VBScript, as it's a not-Mac-compatible technology), so you're on your own in this regard. At the least we can supplement the if (navigator.plugins && navigator.plugins["Shockwave Flash"]) statement, whose condition returns (converts to) false for MSIE for Windows, with a suitable else clause

else document.write("As far as we can tell, you do not have a Flash plug-in. If this is not true, you may access our Flash content via the link below.");

and link

<a href="FLASHPAGE.html">Check out our really cool Flash content.</a>

to bring users of MSIE for Windows (and other browsers not supporting Netscape's plugin object) into the loop.

(I suppose we could just assume that MSIE for Windows users have Flash support and send them to the FLASHPAGE.html page, but that rather defeats the whole point of using a Flash detection script, wouldn't you say?)

In sum, the "Test Visitors for the Flash Plug-In" script should be reducible to a single if...else statement and an anchor element. I acknowledge that my code won't work with all browsers and, unlike the tutorial code, imposes some responsibility on some users although I fail to see how we can avoid that.

Part of the problem in crafting a JavaScript Flash sniffer is that, as of this writing, neither the plugin object nor its navigator object parent is a standard object, raising the question: Where is the W3C on all of this? As you know, most of JavaScript's erstwhile client-side objects were spun off to the DOM around 1998 or so. The window object - the parent of both the document object and the navigator object, and which is also a nonstandard object - can be effectively accessed by the document object via the DOM defaultView property, and you'd think that the W3C would have by now given the document object a property or method allowing it to access the navigator object (e.g., document.getUserAgent( )) - something that ought to be included in the DOM Level 4 Core Specification, eh?

Interestingly, I see that HTML 5 is defining a window object and a navigator object but is, disappointingly, wimping out on defining a plugin object. (Excepting MSIE, all of the OS X GUI browsers on my computer - Safari, Firefox, Opera, Camino, and now Google's Chrome - support the Netscape plugin object API, more specifically, the plugin object and its description, filename, length, and name properties. Isn't it the W3C's job to lay down the law to our friends in Redmond in cases like this?)

What's your version?

In the sixth paragraph of the "Flash Test Page" page, Joe links to a script (actually two scripts, one a JavaScript and one a VBScript) written by Peter-Paul Koch (a.k.a. ppk) that attempts to test for a Flash plug-in and determine its version; in following the latter link, click on the confirm( ) box to get to ppk's "Flash Detect" page. The second paragraph of the "Flash Test Page" page should end with a demo for this script; unfortunately, as for the "Test Visitors for the Flash Plug-In" gateway script, the JavaScript part of the ppk script in the "Flash Test Page" source has been incapacitated by escaping its [ and ] characters to &#91; and &#93;, respectively. ppk's "Flash Detect" page has its own demo, which works fine as far as it goes.

We won't go through ppk's script in this section, but I did want to point out a problem with it. ppk uses the following JavaScript code to read the user's Flash version:

x = navigator.plugins["Shockwave Flash"];
y = x.description;
flashversion = y.charAt(y.indexOf('.')-1);

For the non-MSIE OS X GUI browsers on my computer, navigator.plugins["Shockwave Flash"].description returns Shockwave Flash 10.0 r42, which is assigned to y in the above code. The flashversion = y.charAt(y.indexOf('.')-1); line locates and assigns to flashversion the single character in y to the left of the decimal point; consequently, ppk's demo tells me that I have Flash version 0 installed and not Flash version 10. This is an easy problem to solve; here's one way to do it:

y = navigator.plugins["Shockwave Flash"].description;
flashversionStart = y.lastIndexOf("h") + 2;
flashversion = parseFloat(y.substr(flashversionStart));

flashversionStart = y.lastIndexOf("h") + 2; locates and assigns to flashversionStart the character index in y two places to the right of the last h in Shockwave Flash 10.0 r42, i.e., the index of the 1 that begins the Flash version.
y.substr(flashversionStart) returns the 10.0 r42 substring of Shockwave Flash 10.0 r42.
flashversion = parseFloat(y.substr(flashversionStart)); returns and assigns to flashversion the floating-point numeral at the beginning of 10.0 r42. In practice, document.write(flashversion); displays 10 and not 10.0.

And that wraps up our tour of HTML Goodies' "JavaScript Browser Test Scripts" series of tutorials. In the following entry, we'll take on the next "Beyond HTML : JavaScript" tutorial, "Escape Characters".


Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)