reptile7's JavaScript blog
Friday, January 15, 2010
 
Trawling for Plugins, Part 2
Blog Entry #168

We return now to our ongoing discussion of HTML Goodies' "Test Visitors for the Flash Plug-In" tutorial.

Regarding the provenance of the "Test Visitors for the Flash Plug-In" script, Joe confesses:
Although I enjoy writing most of the JavaScripts distributed on this site, I didn't write this one. In fact, I don't know who did. I found the script by doing a Google search on the words "Detect Flash Plugin." It seems like a stock script because I found it on numerous sites covering several different topics. It was used on at least 20 different sites that I found. At no time did I ever find a copyright or author name. That leads me to believe it's a distributed script. Plus, one must enforce copyright or lose it. I'll be more than pleased to offer the author's name here if he or she can prove authorship to me.
In the "Non-MSIE deconstruction" of the previous post, we bumped up against a pointless custom document object property, a key with statement whose body was not delimited with braces, and a counterintuitive use of logical operators, and I'm sorry to report that the rest of the "Test Visitors for the Flash Plug-In" script mostly goes downhill from there. Indeed, the MSIE part of the script's MM_checkPlugin( ) function strongly suggests that either (a) Joe didn't grab the entire script or (b) the script he grabbed was incomplete to begin with.

MSIE deconstruction

The script's MSIE part begins with the else clause that follows the
if (appName.indexOf("Microsoft") == -1) ok = (plugins && plugins[plgIn]);
statement applying to non-MSIE users.

else if (appVersion.indexOf("3.1") == -1) { // Not Netscape nor Win3.1
... }


The else clause itself comprises an if statement whose condition, if I understand the // Not Netscape nor Win3.1 comment correctly, seeks to exclude users running a Windows 3.1x operating system, the implication being that such users do not have Flash support. The navigator.appVersion string might seem like an odd place to fish for OS information, but the "Additional browsers' Navigator Information" section of JavaScript Kit's "Navigator Object" page confirms that Microsoft does put the user OS in the MSIE for Windows navigator.appVersion and navigator.userAgent returns. BTW, version-wise, there was no MSIE 3.1x for either Windows or Mac.

You may be wondering, "If we're going to 'platform sniff', why not use the platform property of the navigator object?" As it happens, a platform != "Win16" if condition would also exclude Windows 3.1x users, although it's not clear that this test would offer any advantages over the script's appVersion-based test.

I'm not so sure we should be locking out Windows 3.1x users, however. According to Wikipedia, Microsoft released versions of Internet Explorer from 2.0 up to the first release of Internet Explorer 5.0 for Windows 3.1, and I would be highly surprised if MSIE 4.x and MSIE 5.0 and maybe even MSIE 3.03 for Windows 3.1 - browsers that were contemporaneous with the early Flash players - could not handle at least some Flash content (but I don't know for certain).

Anyway, let's move on. Next up we have two if statements that are, shall we say, out of time and out of place. Here's the first one:

if (plgIn.indexOf("Flash") != -1 && window.MM_flash != null)
ok = window.MM_flash;


• The plgIn.indexOf("Flash") != -1 subcondition necessarily returns true; plgIn necessarily contains Flash as we assigned Shockwave Flash to plgIn when we called the MM_checkPlugin( ) function.

• The window.MM_flash != null subcondition tests if MM_flash, a custom one-off property that is given to the window object and that is not declared earlier in the script - it just appears out of the blue at this point in the code - is not equal to null. As you would expect, the window.MM_flash expression evaluates to undefined; consequently, this subcondition returns false because the undefined and null values are equal in the context of an == or != comparison.

• The if condition as a whole (true && false) returns false, and thus window.MM_flash is not assigned to ok.

The following if statement is even weirder:

else if (plgIn.indexOf("Director") != -1 && window.MM_dir != null)
ok = window.MM_dir;


These lines of code lead one to suspect that an alternate version of the "Test Visitors for the Flash Plug-In" script (wherever it came from) tested for the Shockwave for Director plug-in, which is not the same as the Flash plug-in. But for our present purposes:

• The plgIn.indexOf("Director") != -1 subcondition returns false - as noted above, plgIn's value is Shockwave Flash.

• The window.MM_dir != null subcondition features yet another custom one-off property, MM_dir, which like MM_flash is tacked onto the window object and again appears out of the blue; this subcondition returns false for the same reason that the window.MM_flash != null subcondition returns false.

• The overall if condition (false && false) returns false, and therefore window.MM_dir isn't assigned to ok either.

Control now passes to the else clause that concludes the script's MSIE part:

else ok = autoGo;

The above line sets ok to true, which was assigned to autoGo when we called the MM_checkPlugin( ) function, for all MSIE users not running Windows 3.1x, which should be pretty much all MSIE users at this point in time. It is left to the reader to verify that the script's window.location = theURL; redirection command subsequently sends those MSIE users to the FLASHPAGE.html page whether they have a Flash plug-in or not, an outcome constituting a false positive for MSIE users without Flash support and that we might term an 'accidental positive' for MSIE users with Flash support in the sense that, unlike its non-MSIE part, the script's MSIE part does not actually test for the Flash plug-in.

The meta that refreshes

Recognizing that Flash cannot be detected by some browsers, Joe added to the "Test Visitors for the Flash Plug-In" script a "meta refresh" that sends users of such browsers to the NON-FLASHPAGE.html page after an eight-second delay:

<meta http-equiv="refresh" content="8; url=NON-FLASHPAGE.html" />

I can't recall ever discussing the meta element on this blog before, so let me say a few things about it. The HTML meta element provides a mechanism for specifying document metadata: data about a document as opposed to actual document content. The meta element specifies a document metadata property via a name or http-equiv attribute and a value for that property via a content attribute, e.g.:

<meta name="author" content="Joe Burns" />

(Conceptually, this is a lot like adding a custom one-off property to the document object, i.e., document.author = "Joe Burns";.)

The meta element is an empty element that, like the title and style elements (which are also metadata-type elements), must appear in the document head. Historically, the meta element and its name/http-equiv/content attributes go back at least as far as HTML 2.0 and maybe earlier.

HTML Goodies offers two tutorials dealing with the meta element:
(1) The use of meta elements to facilitate the indexing of Web pages by search engines - the most common application of the meta element - is discussed in "So, You Want A Meta Command, Huh?".
(2) Apropos the "Test Visitors for the Flash Plug-In" script, the use of meta elements to create "dynamic documents" is discussed in "So, You Want A Dynamic Page, Huh?".

So, what's the story with a meta refresh? How does it work? The http-equiv attribute and its value simulate (but do not actually generate) an HTTP response header for specifying metadata of some sort, e.g., Content-Language, Date, Last-Modified, etc. The Refresh header (which admittedly seems much more like a 'method' than a 'property') indicates that the served document is not meant to be static but should be "refreshed" in some way, i.e., either reloaded or replaced by another document after a given period of time. If Refresh is set to someInteger
<meta http-equiv="refresh" content="5" />
then the current page will reload after someInteger seconds; alternatively, if Refresh is set to someInteger; url=someURL
<meta http-equiv="refresh" content="5; url=http://www.w3.org/" />
then the user will be redirected to someURL after someInteger seconds.

Refresh is not a standard HTTP header - you won't find it in Section 14 ("Header Field Definitions") of the HTTP/1.1 RFC - but was implemented proprietarily by Netscape and currently has cross-browser support, although I wouldn't count on that support continuing indefinitely. For accessibility reasons, the W3C frowns on meta refreshes and has even deprecated them. Moreover, Microsoft maintains an "HTTP Response Headers" page on which the Refresh header is termed "obsolete".

As noted in the previous post, the "Test Visitors for the Flash Plug-In" script in the source of the "Test Visitors for the Flash Plug-In" 'gateway page' is defective; consequently, upon accessing the gateway page, the script's meta refresh kicks in, sending most browsers to the script's 'You don't have Flash' page, notwithstanding the fact that the someURL substring in the content value, /beyond/javascript/article.php/3470931 in this case, is supposed to be an absolute URL and not a relative URL. Conversely, Joe avers that text-only browsers cannot support the [meta redirection] command in "Tip Sixteen" of his "So You Want To Get Them All The Same, Huh?" collection of cross-browser coding guidelines, and I can confirm that Lynx 2.8.7 recognizes but does not act on a meta redirect. At the "Test Visitors for the Flash Plug-In" gateway page, Lynx transiently displays a Refresh URL is not absolute message while the page loads. At the "So, You Want A Dynamic Page, Huh?" tutorial, which features a
<meta http-equiv="refresh" content="1; url=http://www.htmlgoodies.com/tada.au" />
meta redirect with an absolute URL, Lynx writes to standard output a REFRESH(1 sec): http://www.htmlgoodies.com/tada.au message but does not go on to the tada.au page.

Now having checked over the "Test Visitors for the Flash Plug-In" script in its entirety, our remaining task is to clean the script up, and we'll do that in the following entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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